aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS5
-rw-r--r--Documentation/IRQ-domain.txt34
-rw-r--r--Documentation/cgroups/memory.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-at91.txt6
-rw-r--r--Documentation/devicetree/bindings/clock/imx23-clock.txt2
-rw-r--r--Documentation/devicetree/bindings/clock/imx28-clock.txt4
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio.txt36
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio_atmel.txt5
-rw-r--r--Documentation/devicetree/bindings/mmc/mmc.txt8
-rw-r--r--Documentation/devicetree/bindings/mmc/samsung-sdhci.txt20
-rw-r--r--Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt (renamed from Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt)0
-rw-r--r--Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt1
-rw-r--r--Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt23
-rw-r--r--Documentation/devicetree/bindings/net/mdio-gpio.txt9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt141
-rw-r--r--Documentation/filesystems/proc.txt16
-rw-r--r--Documentation/gpio.txt42
-rw-r--r--Documentation/hwmon/ads782846
-rw-r--r--Documentation/hwmon/coretemp2
-rw-r--r--Documentation/hwmon/da905547
-rw-r--r--Documentation/mmc/mmc-dev-attrs.txt7
-rw-r--r--Documentation/networking/netdev-features.txt2
-rw-r--r--Documentation/networking/vxlan.txt4
-rw-r--r--Documentation/pinctrl.txt7
-rw-r--r--MAINTAINERS112
-rw-r--r--Makefile8
-rw-r--r--arch/alpha/kernel/osf_sys.c6
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/boot/Makefile10
-rw-r--r--arch/arm/boot/compressed/head.S14
-rw-r--r--arch/arm/boot/dts/Makefile48
-rw-r--r--arch/arm/boot/dts/animeo_ip.dts178
-rw-r--r--arch/arm/boot/dts/at91rm9200.dtsi349
-rw-r--r--arch/arm/boot/dts/at91rm9200ek.dts79
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi295
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi299
-rw-r--r--arch/arm/boot/dts/at91sam9263ek.dts29
-rw-r--r--arch/arm/boot/dts/at91sam9g15.dtsi28
-rw-r--r--arch/arm/boot/dts/at91sam9g15ek.dts16
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_2mmc.dts26
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi30
-rw-r--r--arch/arm/boot/dts/at91sam9g25.dtsi28
-rw-r--r--arch/arm/boot/dts/at91sam9g25ek.dts49
-rw-r--r--arch/arm/boot/dts/at91sam9g35.dtsi28
-rw-r--r--arch/arm/boot/dts/at91sam9g35ek.dts16
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi301
-rw-r--r--arch/arm/boot/dts/at91sam9m10g45ek.dts48
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi225
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts22
-rw-r--r--arch/arm/boot/dts/at91sam9x25.dtsi49
-rw-r--r--arch/arm/boot/dts/at91sam9x25ek.dts16
-rw-r--r--arch/arm/boot/dts/at91sam9x35.dtsi28
-rw-r--r--arch/arm/boot/dts/at91sam9x35ek.dts16
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi270
-rw-r--r--arch/arm/boot/dts/at91sam9x5ek.dtsi101
-rw-r--r--arch/arm/boot/dts/pm9g45.dts165
-rw-r--r--arch/arm/boot/dts/spear1310-evb.dts4
-rw-r--r--arch/arm/boot/dts/spear1310.dtsi27
-rw-r--r--arch/arm/boot/dts/spear1340-evb.dts4
-rw-r--r--arch/arm/boot/dts/spear1340.dtsi26
-rw-r--r--arch/arm/boot/dts/spear310.dtsi22
-rw-r--r--arch/arm/boot/dts/spear320-evb.dts4
-rw-r--r--arch/arm/boot/dts/spear320.dtsi23
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi4
-rw-r--r--arch/arm/common/timer-sp.c2
-rw-r--r--arch/arm/configs/at91_dt_defconfig1
-rw-r--r--arch/arm/include/asm/hardware/sp810.h2
-rw-r--r--arch/arm/mach-at91/Kconfig9
-rw-r--r--arch/arm/mach-at91/Makefile1
-rw-r--r--arch/arm/mach-at91/at91rm9200.c22
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c2
-rw-r--r--arch/arm/mach-at91/at91rm9200_time.c63
-rw-r--r--arch/arm/mach-at91/at91sam9260.c8
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9261.c4
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9263.c11
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c12
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c12
-rw-r--r--arch/arm/mach-at91/at91sam9n12.c16
-rw-r--r--arch/arm/mach-at91/at91sam9rl.c4
-rw-r--r--arch/arm/mach-at91/at91sam9x5.c21
-rw-r--r--arch/arm/mach-at91/board-dt.c2
-rw-r--r--arch/arm/mach-at91/board-rm9200-dt.c57
-rw-r--r--arch/arm/mach-at91/generic.h1
-rw-r--r--arch/arm/mach-at91/gpio.c190
-rw-r--r--arch/arm/mach-at91/include/mach/board.h10
-rw-r--r--arch/arm/mach-at91/setup.c20
-rw-r--r--arch/arm/mach-at91/soc.h12
-rw-r--r--arch/arm/mach-davinci/dm644x.c3
-rw-r--r--arch/arm/mach-dove/include/mach/pm.h2
-rw-r--r--arch/arm/mach-dove/irq.c14
-rw-r--r--arch/arm/mach-exynos/dma.c3
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h1
-rw-r--r--arch/arm/mach-highbank/system.c3
-rw-r--r--arch/arm/mach-imx/clk-gate2.c2
-rw-r--r--arch/arm/mach-imx/ehci-imx25.c2
-rw-r--r--arch/arm/mach-imx/ehci-imx35.c2
-rw-r--r--arch/arm/mach-integrator/impd1.c69
-rw-r--r--arch/arm/mach-ixp4xx/common-pci.c1
-rw-r--r--arch/arm/mach-ixp4xx/common.c13
-rw-r--r--arch/arm/mach-ixp4xx/goramo_mlr.c3
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/debug-macro.S4
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h46
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/qmgr.h12
-rw-r--r--arch/arm/mach-ixp4xx/ixp4xx_npe.c9
-rw-r--r--arch/arm/mach-ixp4xx/ixp4xx_qmgr.c12
-rw-r--r--arch/arm/mach-kirkwood/pcie.c11
-rw-r--r--arch/arm/mach-nomadik/board-nhk8815.c3
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c2
-rw-r--r--arch/arm/mach-nomadik/i2c-8815nhk.c3
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c5
-rw-r--r--arch/arm/mach-omap2/clockdomains44xx_data.c2
-rw-r--r--arch/arm/mach-omap2/common-board-devices.c34
-rw-r--r--arch/arm/mach-omap2/devices.c79
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c63
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c36
-rw-r--r--arch/arm/mach-omap2/twl-common.c3
-rw-r--r--arch/arm/mach-omap2/vc.c2
-rw-r--r--arch/arm/mach-pxa/hx4700.c8
-rw-r--r--arch/arm/mach-pxa/spitz_pm.c8
-rw-r--r--arch/arm/mach-u300/core.c5
-rw-r--r--arch/arm/mach-u300/include/mach/irqs.h126
-rw-r--r--arch/arm/mach-ux500/board-mop500-audio.c3
-rw-r--r--arch/arm/mach-ux500/board-mop500-pins.c3
-rw-r--r--arch/arm/mach-ux500/board-mop500.c2
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c12
-rw-r--r--arch/arm/mach-ux500/devices-common.c3
-rw-r--r--arch/arm/mach-ux500/devices-common.h8
-rw-r--r--arch/arm/mm/proc-v6.S2
-rw-r--r--arch/arm/plat-nomadik/include/plat/gpio-nomadik.h102
-rw-r--r--arch/arm/plat-omap/i2c.c21
-rw-r--r--arch/arm/plat-omap/include/plat/mmc.h1
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h6
-rw-r--r--arch/arm/plat-s3c24xx/dma.c9
-rw-r--r--arch/arm/tools/Makefile2
-rw-r--r--arch/arm64/include/asm/io.h2
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h6
-rw-r--r--arch/arm64/include/asm/pgtable.h40
-rw-r--r--arch/arm64/include/asm/unistd32.h2
-rw-r--r--arch/c6x/include/asm/setup.h33
-rw-r--r--arch/c6x/include/uapi/asm/Kbuild2
-rw-r--r--arch/c6x/include/uapi/asm/kvm_para.h1
-rw-r--r--arch/c6x/include/uapi/asm/setup.h33
-rw-r--r--arch/c6x/kernel/entry.S5
-rw-r--r--arch/ia64/mm/init.c1
-rw-r--r--arch/m68k/include/asm/signal.h6
-rw-r--r--arch/microblaze/kernel/signal.c2
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-l2c.c1
-rw-r--r--arch/mips/fw/arc/misc.c1
-rw-r--r--arch/mips/include/asm/bitops.h128
-rw-r--r--arch/mips/include/asm/compat.h2
-rw-r--r--arch/mips/include/asm/hugetlb.h12
-rw-r--r--arch/mips/include/asm/io.h1
-rw-r--r--arch/mips/include/asm/irqflags.h207
-rw-r--r--arch/mips/include/asm/thread_info.h6
-rw-r--r--arch/mips/kernel/cpu-probe.c1
-rw-r--r--arch/mips/kernel/entry.S7
-rw-r--r--arch/mips/kernel/scall64-n32.S6
-rw-r--r--arch/mips/kernel/setup.c26
-rw-r--r--arch/mips/lib/Makefile5
-rw-r--r--arch/mips/lib/bitops.c179
-rw-r--r--arch/mips/lib/mips-atomic.c176
-rw-r--r--arch/mips/mm/tlb-r4k.c18
-rw-r--r--arch/mips/mti-malta/malta-platform.c3
-rw-r--r--arch/openrisc/kernel/signal.c6
-rw-r--r--arch/parisc/kernel/signal32.c6
-rw-r--r--arch/parisc/kernel/sys_parisc.c2
-rw-r--r--arch/parisc/kernel/syscall_table.S2
-rw-r--r--arch/powerpc/boot/dts/mpc5200b.dtsi6
-rw-r--r--arch/powerpc/boot/dts/o2d.dtsi6
-rw-r--r--arch/powerpc/boot/dts/pcm030.dts7
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c9
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pe.c2
-rw-r--r--arch/powerpc/platforms/pseries/msi.c3
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/include/asm/compat.h2
-rw-r--r--arch/s390/include/asm/topology.h3
-rw-r--r--arch/s390/include/uapi/asm/ptrace.h4
-rw-r--r--arch/s390/kernel/compat_signal.c14
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/signal.c14
-rw-r--r--arch/s390/kernel/topology.c6
-rw-r--r--arch/s390/mm/gup.c5
-rw-r--r--arch/score/kernel/signal.c7
-rw-r--r--arch/sh/kernel/signal_64.c6
-rw-r--r--arch/sparc/boot/piggyback.c12
-rw-r--r--arch/sparc/include/asm/prom.h5
-rw-r--r--arch/sparc/kernel/signal_64.c4
-rw-r--r--arch/sparc/kernel/sys32.S2
-rw-r--r--arch/sparc/kernel/syscalls.S14
-rw-r--r--arch/sparc/kernel/systbls_64.S2
-rw-r--r--arch/um/kernel/exec.c3
-rw-r--r--arch/unicore32/Kconfig7
-rw-r--r--arch/unicore32/include/asm/Kbuild1
-rw-r--r--arch/unicore32/include/asm/bug.h5
-rw-r--r--arch/unicore32/include/asm/cmpxchg.h2
-rw-r--r--arch/unicore32/include/asm/kvm_para.h1
-rw-r--r--arch/unicore32/include/asm/processor.h5
-rw-r--r--arch/unicore32/include/asm/ptrace.h76
-rw-r--r--arch/unicore32/include/uapi/asm/Kbuild7
-rw-r--r--arch/unicore32/include/uapi/asm/byteorder.h (renamed from arch/unicore32/include/asm/byteorder.h)0
-rw-r--r--arch/unicore32/include/uapi/asm/ptrace.h90
-rw-r--r--arch/unicore32/include/uapi/asm/sigcontext.h (renamed from arch/unicore32/include/asm/sigcontext.h)0
-rw-r--r--arch/unicore32/include/uapi/asm/unistd.h (renamed from arch/unicore32/include/asm/unistd.h)1
-rw-r--r--arch/unicore32/kernel/entry.S20
-rw-r--r--arch/unicore32/kernel/process.c58
-rw-r--r--arch/unicore32/kernel/setup.h6
-rw-r--r--arch/unicore32/kernel/sys.c63
-rw-r--r--arch/unicore32/mm/fault.c37
-rw-r--r--arch/x86/boot/compressed/eboot.c2
-rw-r--r--arch/x86/boot/header.S3
-rw-r--r--arch/x86/include/asm/Kbuild3
-rw-r--r--arch/x86/include/asm/fpu-internal.h15
-rw-r--r--arch/x86/include/asm/ptrace.h15
-rw-r--r--arch/x86/kernel/cpu/amd.c14
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_intel.c31
-rw-r--r--arch/x86/kernel/entry_64.S14
-rw-r--r--arch/x86/kernel/head_32.S9
-rw-r--r--arch/x86/kernel/microcode_amd.c8
-rw-r--r--arch/x86/kernel/ptrace.c37
-rw-r--r--arch/x86/kernel/smpboot.c5
-rw-r--r--arch/x86/kvm/cpuid.h3
-rw-r--r--arch/x86/kvm/emulate.c3
-rw-r--r--arch/x86/kvm/vmx.c11
-rw-r--r--arch/x86/kvm/x86.c3
-rw-r--r--arch/x86/mm/tlb.c2
-rw-r--r--arch/x86/pci/ce4100.c13
-rw-r--r--arch/x86/platform/ce4100/ce4100.c24
-rw-r--r--block/blk-exec.c8
-rw-r--r--drivers/ata/ahci_platform.c2
-rw-r--r--drivers/ata/libata-acpi.c11
-rw-r--r--drivers/ata/libata-core.c4
-rw-r--r--drivers/ata/libata-scsi.c2
-rw-r--r--drivers/ata/pata_arasan_cf.c8
-rw-r--r--drivers/ata/sata_highbank.c4
-rw-r--r--drivers/ata/sata_svw.c35
-rw-r--r--drivers/atm/ambassador.c1
-rw-r--r--drivers/base/dma-contiguous.c24
-rw-r--r--drivers/base/power/qos.c2
-rw-r--r--drivers/block/aoe/aoecmd.c2
-rw-r--r--drivers/block/floppy.c5
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c18
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h6
-rw-r--r--drivers/bluetooth/ath3k.c1
-rw-r--r--drivers/bluetooth/btusb.c1
-rw-r--r--drivers/bus/omap-ocp2scp.c68
-rw-r--r--drivers/char/hw_random/Kconfig6
-rw-r--r--drivers/char/hw_random/ixp4xx-rng.c5
-rw-r--r--drivers/char/raw.c2
-rw-r--r--drivers/clk/Kconfig16
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-bcm2835.c8
-rw-r--r--drivers/clk/clk-fixed-rate.c2
-rw-r--r--drivers/clk/clk-prima2.c84
-rw-r--r--drivers/clk/clk-twl6040.c126
-rw-r--r--drivers/clk/clk-vt8500.c18
-rw-r--r--drivers/clk/clk-wm831x.c34
-rw-r--r--drivers/clk/clk.c154
-rw-r--r--drivers/clk/mxs/clk-imx23.c6
-rw-r--r--drivers/clk/mxs/clk-imx28.c10
-rw-r--r--drivers/clk/spear/clk-aux-synth.c3
-rw-r--r--drivers/clk/spear/clk-vco-pll.c2
-rw-r--r--drivers/clk/spear/clk.c3
-rw-r--r--drivers/clk/spear/spear1310_clock.c106
-rw-r--r--drivers/clk/spear/spear1340_clock.c237
-rw-r--r--drivers/clk/spear/spear3xx_clock.c154
-rw-r--r--drivers/clk/spear/spear6xx_clock.c13
-rw-r--r--drivers/clk/ux500/Makefile3
-rw-r--r--drivers/clk/ux500/abx500-clk.c73
-rw-r--r--drivers/clk/ux500/clk-prcmu.c72
-rw-r--r--drivers/clk/ux500/clk.h12
-rw-r--r--drivers/clk/ux500/u8500_clk.c78
-rw-r--r--drivers/clk/versatile/Makefile3
-rw-r--r--drivers/clk/versatile/clk-icst.c66
-rw-r--r--drivers/clk/versatile/clk-icst.h14
-rw-r--r--drivers/clk/versatile/clk-impd1.c97
-rw-r--r--drivers/clk/versatile/clk-integrator.c55
-rw-r--r--drivers/clk/versatile/clk-realview.c65
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c146
-rw-r--r--drivers/clk/versatile/clk-vexpress.c142
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c101
-rw-r--r--drivers/crypto/Kconfig2
-rw-r--r--drivers/crypto/ixp4xx_crypto.c12
-rw-r--r--drivers/edac/Kconfig8
-rw-r--r--drivers/edac/amd64_edac.c297
-rw-r--r--drivers/edac/amd64_edac.h61
-rw-r--r--drivers/edac/amd64_edac_inj.c128
-rw-r--r--drivers/edac/edac_mc.c65
-rw-r--r--drivers/edac/edac_mc_sysfs.c39
-rw-r--r--drivers/edac/edac_module.c27
-rw-r--r--drivers/edac/edac_pci.c3
-rw-r--r--drivers/edac/edac_pci_sysfs.c12
-rw-r--r--drivers/edac/edac_stub.c2
-rw-r--r--drivers/edac/highbank_mc_edac.c8
-rw-r--r--drivers/edac/i7300_edac.c8
-rw-r--r--drivers/edac/i7core_edac.c6
-rw-r--r--drivers/edac/i82975x_edac.c11
-rw-r--r--drivers/edac/mce_amd.c254
-rw-r--r--drivers/edac/mce_amd.h11
-rw-r--r--drivers/edac/mce_amd_inj.c4
-rw-r--r--drivers/firewire/sbp2.c2
-rw-r--r--drivers/gpio/Kconfig2
-rw-r--r--drivers/gpio/gpio-mcp23s08.c6
-rw-r--r--drivers/gpio/gpio-mvebu.c23
-rw-r--r--drivers/gpio/gpiolib-of.c52
-rw-r--r--drivers/gpio/gpiolib.c76
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c1
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c6
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c11
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c11
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c12
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c19
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c12
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.c4
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.h2
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/object.h14
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/clock.h3
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c2
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c19
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c3
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c48
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c2
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_agp.c5
-rw-r--r--drivers/gpu/drm/ttm/ttm_page_alloc.c5
-rw-r--r--drivers/gpu/drm/ttm/ttm_tt.c4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c2
-rw-r--r--drivers/hid/hid-microsoft.c6
-rw-r--r--drivers/hwmon/Kconfig19
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/ads7828.c247
-rw-r--r--drivers/hwmon/coretemp.c60
-rw-r--r--drivers/hwmon/da9052-hwmon.c27
-rw-r--r--drivers/hwmon/da9055-hwmon.c336
-rw-r--r--drivers/hwmon/fam15h_power.c4
-rw-r--r--drivers/hwmon/ina2xx.c13
-rw-r--r--drivers/i2c/busses/i2c-at91.c7
-rw-r--r--drivers/i2c/busses/i2c-mxs.c2
-rw-r--r--drivers/i2c/busses/i2c-omap.c36
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c1
-rw-r--r--drivers/i2c/muxes/i2c-mux-pinctrl.c2
-rw-r--r--drivers/input/input-mt.c4
-rw-r--r--drivers/input/matrix-keymap.c3
-rw-r--r--drivers/input/mousedev.c4
-rw-r--r--drivers/input/touchscreen/ads7846.c6
-rw-r--r--drivers/iommu/intel-iommu.c4
-rw-r--r--drivers/iommu/tegra-smmu.c1
-rw-r--r--drivers/irqchip/irq-bcm2835.c3
-rw-r--r--drivers/leds/ledtrig-cpu.c21
-rw-r--r--drivers/md/dm.c8
-rw-r--r--drivers/md/md.c27
-rw-r--r--drivers/md/raid1.c2
-rw-r--r--drivers/md/raid10.c133
-rw-r--r--drivers/md/raid5.c79
-rw-r--r--drivers/media/dvb-frontends/stv0900_core.c6
-rw-r--r--drivers/media/i2c/adv7604.c377
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c11
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c6
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c4
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-regs.h16
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c4
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c4
-rw-r--r--drivers/media/platform/omap3isp/ispstat.h4
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c2
-rw-r--r--drivers/media/platform/s5p-fimc/Kconfig1
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-capture.c14
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-lite.c10
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-m2m.c3
-rw-r--r--drivers/media/platform/s5p-fimc/fimc-mdevice.c41
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c7
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c2
-rw-r--r--drivers/media/platform/sh_vou.c3
-rw-r--r--drivers/media/platform/soc_camera/mx1_camera.c9
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c13
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c5
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c13
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c11
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c4
-rw-r--r--drivers/mfd/arizona-core.c14
-rw-r--r--drivers/mfd/arizona-irq.c1
-rw-r--r--drivers/mfd/db8500-prcmu.c86
-rw-r--r--drivers/mfd/twl-core.c2
-rw-r--r--drivers/mfd/twl4030-irq.c3
-rw-r--r--drivers/mfd/wm5102-tables.c519
-rw-r--r--drivers/mmc/card/block.c81
-rw-r--r--drivers/mmc/card/queue.c17
-rw-r--r--drivers/mmc/core/bus.c3
-rw-r--r--drivers/mmc/core/core.c32
-rw-r--r--drivers/mmc/core/debugfs.c16
-rw-r--r--drivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/mmc_ops.c11
-rw-r--r--drivers/mmc/core/sdio_bus.c17
-rw-r--r--drivers/mmc/core/sdio_io.c10
-rw-r--r--drivers/mmc/core/sdio_ops.c32
-rw-r--r--drivers/mmc/core/slot-gpio.c8
-rw-r--r--drivers/mmc/host/Kconfig33
-rw-r--r--drivers/mmc/host/Makefile2
-rw-r--r--drivers/mmc/host/at91_mci.c1219
-rw-r--r--drivers/mmc/host/at91_mci.h115
-rw-r--r--drivers/mmc/host/dw_mmc-pci.c2
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c16
-rw-r--r--drivers/mmc/host/dw_mmc.c86
-rw-r--r--drivers/mmc/host/mxcmmc.c2
-rw-r--r--drivers/mmc/host/mxs-mmc.c31
-rw-r--r--drivers/mmc/host/omap_hsmmc.c177
-rw-r--r--drivers/mmc/host/sdhci-dove.c108
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c56
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c54
-rw-r--r--drivers/mmc/host/sdhci-pci.c1
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c9
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c13
-rw-r--r--drivers/mmc/host/sdhci-s3c.c65
-rw-r--r--drivers/mmc/host/sdhci-spear.c9
-rw-r--r--drivers/mmc/host/sdhci.c79
-rw-r--r--drivers/mmc/host/sdhci.h5
-rw-r--r--drivers/mmc/host/sh_mmcif.c14
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c8
-rw-r--r--drivers/mmc/host/vub300.c1
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c1029
-rw-r--r--drivers/mtd/devices/slram.c2
-rw-r--r--drivers/mtd/mtdcore.c6
-rw-r--r--drivers/mtd/nand/atmel_nand.c9
-rw-r--r--drivers/mtd/nand/nand_base.c10
-rw-r--r--drivers/mtd/ofpart.c2
-rw-r--r--drivers/mtd/onenand/onenand_base.c2
-rw-r--r--drivers/mtd/ubi/wl.c26
-rw-r--r--drivers/net/bonding/bond_main.c100
-rw-r--r--drivers/net/bonding/bond_sysfs.c36
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb.c8
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c8
-rw-r--r--drivers/net/ethernet/8390/ne.c1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c11
-rw-r--r--drivers/net/ethernet/jme.c28
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c2
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c16
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c33
-rw-r--r--drivers/net/ethernet/sis/sis900.c2
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c17
-rw-r--r--drivers/net/ethernet/tile/tilegx.c2
-rw-r--r--drivers/net/ethernet/xilinx/xilinx_axienet_main.c14
-rw-r--r--drivers/net/ethernet/xscale/ixp4xx_eth.c8
-rw-r--r--drivers/net/irda/sir_dev.c2
-rw-r--r--drivers/net/phy/mdio-bitbang.c1
-rw-r--r--drivers/net/phy/mdio-gpio.c11
-rw-r--r--drivers/net/team/team.c4
-rw-r--r--drivers/net/team/team_mode_broadcast.c6
-rw-r--r--drivers/net/usb/cdc_ncm.c22
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/usb/smsc95xx.c4
-rw-r--r--drivers/net/vxlan.c10
-rw-r--r--drivers/net/wan/ixp4xx_hss.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c16
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/rxon.c12
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/rx.c23
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c8
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c11
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c11
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/net/xen-netfront.c98
-rw-r--r--drivers/nfc/pn533.c25
-rw-r--r--drivers/pinctrl/Kconfig52
-rw-r--r--drivers/pinctrl/Makefile7
-rw-r--r--drivers/pinctrl/core.c58
-rw-r--r--drivers/pinctrl/core.h2
-rw-r--r--drivers/pinctrl/devicetree.c11
-rw-r--r--drivers/pinctrl/mvebu/Kconfig24
-rw-r--r--drivers/pinctrl/mvebu/Makefile5
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-370.c (renamed from drivers/pinctrl/pinctrl-armada-370.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-xp.c (renamed from drivers/pinctrl/pinctrl-armada-xp.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-dove.c (renamed from drivers/pinctrl/pinctrl-dove.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-kirkwood.c (renamed from drivers/pinctrl/pinctrl-kirkwood.c)0
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c (renamed from drivers/pinctrl/pinctrl-mvebu.c)1
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.h (renamed from drivers/pinctrl/pinctrl-mvebu.h)0
-rw-r--r--drivers/pinctrl/pinconf-generic.c1
-rw-r--r--drivers/pinctrl/pinctrl-at91.c1634
-rw-r--r--drivers/pinctrl/pinctrl-bcm2835.c2
-rw-r--r--drivers/pinctrl/pinctrl-coh901.c175
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c1
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c2
-rw-r--r--drivers/pinctrl/pinctrl-imx.c4
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.c23
-rw-r--r--drivers/pinctrl/pinctrl-mxs.c2
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8500.c125
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8540.c16
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c152
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.h2
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.c12
-rw-r--r--drivers/pinctrl/pinctrl-pxa3xx.h2
-rw-r--r--drivers/pinctrl/pinctrl-single.c90
-rw-r--r--drivers/pinctrl/pinctrl-sirf.c52
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c24
-rw-r--r--drivers/pinctrl/pinctrl-u300.c97
-rw-r--r--drivers/pinctrl/pinctrl-xway.c2
-rw-r--r--drivers/pinctrl/pinmux.c85
-rw-r--r--drivers/pinctrl/spear/Kconfig11
-rw-r--r--drivers/pinctrl/spear/Makefile1
-rw-r--r--drivers/pinctrl/spear/pinctrl-plgpio.c758
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c131
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.h60
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear1310.c264
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear1340.c27
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear300.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear310.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear320.c2
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.c37
-rw-r--r--drivers/rapidio/rio.c2
-rw-r--r--drivers/regulator/core.c33
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c18
-rw-r--r--drivers/rtc/rtc-tps65910.c6
-rw-r--r--drivers/s390/char/con3215.c12
-rw-r--r--drivers/s390/net/qeth_core_main.c24
-rw-r--r--drivers/s390/net/qeth_l2_main.c13
-rw-r--r--drivers/scsi/isci/request.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c14
-rw-r--r--drivers/scsi/scsi.c45
-rw-r--r--drivers/scsi/scsi_lib.c22
-rw-r--r--drivers/scsi/sd.c202
-rw-r--r--drivers/scsi/sd.h7
-rw-r--r--drivers/staging/android/android_alarm.h4
-rw-r--r--drivers/target/target_core_transport.c6
-rw-r--r--drivers/tty/hvc/hvc_console.c7
-rw-r--r--drivers/tty/serial/atmel_serial.c8
-rw-r--r--drivers/tty/serial/max310x.c1
-rw-r--r--drivers/tty/vt/vt.c8
-rw-r--r--drivers/usb/core/hcd.c16
-rw-r--r--drivers/usb/early/ehci-dbgp.c15
-rw-r--r--drivers/usb/host/ehci-ls1x.c2
-rw-r--r--drivers/usb/host/ohci-xls.c2
-rw-r--r--drivers/usb/musb/musb_gadget.c30
-rw-r--r--drivers/usb/musb/ux500.c2
-rw-r--r--drivers/usb/otg/Kconfig4
-rw-r--r--drivers/usb/serial/keyspan.c3
-rw-r--r--drivers/usb/serial/option.c9
-rw-r--r--drivers/usb/serial/usb_wwan.c10
-rw-r--r--drivers/usb/storage/scsiglue.c6
-rw-r--r--drivers/vhost/vhost.c2
-rw-r--r--drivers/video/omap2/dss/dsi.c13
-rw-r--r--drivers/video/omap2/dss/dss.c18
-rw-r--r--drivers/video/omap2/dss/hdmi.c4
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c2
-rw-r--r--drivers/xen/privcmd.c18
-rw-r--r--fs/block_dev.c166
-rw-r--r--fs/buffer.c145
-rw-r--r--fs/cifs/file.c6
-rw-r--r--fs/cifs/readdir.c5
-rw-r--r--fs/cifs/smb1ops.c3
-rw-r--r--fs/direct-io.c8
-rw-r--r--fs/ext3/balloc.c5
-rw-r--r--fs/file.c15
-rw-r--r--fs/fs-writeback.c2
-rw-r--r--fs/inode.c16
-rw-r--r--fs/internal.h1
-rw-r--r--fs/jbd/transaction.c2
-rw-r--r--fs/jffs2/file.c39
-rw-r--r--fs/namei.c5
-rw-r--r--fs/nfs/dir.c7
-rw-r--r--fs/notify/fanotify/fanotify_user.c3
-rw-r--r--fs/proc/base.c114
-rw-r--r--fs/pstore/platform.c3
-rw-r--r--fs/reiserfs/inode.c10
-rw-r--r--fs/reiserfs/stree.c4
-rw-r--r--fs/reiserfs/super.c60
-rw-r--r--fs/ubifs/find.c12
-rw-r--r--fs/ubifs/lprops.c6
-rw-r--r--fs/ubifs/ubifs.h3
-rw-r--r--fs/xfs/xfs_aops.c54
-rw-r--r--fs/xfs/xfs_attr_leaf.c20
-rw-r--r--fs/xfs/xfs_buf.c14
-rw-r--r--include/asm-generic/gpio.h47
-rw-r--r--include/drm/drm_pciids.h1
-rw-r--r--include/linux/bug.h1
-rw-r--r--include/linux/clk-provider.h24
-rw-r--r--include/linux/dma-contiguous.h4
-rw-r--r--include/linux/edac.h3
-rw-r--r--include/linux/fs.h5
-rw-r--r--include/linux/gfp.h5
-rw-r--r--include/linux/gpio.h21
-rw-r--r--include/linux/hw_breakpoint.h31
-rw-r--r--include/linux/i2c-omap.h1
-rw-r--r--include/linux/kernel.h7
-rw-r--r--include/linux/mempolicy.h16
-rw-r--r--include/linux/mfd/db8500-prcmu.h4
-rw-r--r--include/linux/mfd/dbx500-prcmu.h10
-rw-r--r--include/linux/mm.h4
-rw-r--r--include/linux/mmc/card.h2
-rw-r--r--include/linux/mmc/core.h2
-rw-r--r--include/linux/mmc/dw_mmc.h5
-rw-r--r--include/linux/mmc/host.h17
-rw-r--r--include/linux/mmc/mmc.h2
-rw-r--r--include/linux/mmc/mxs-mmc.h19
-rw-r--r--include/linux/mmc/sdhci.h6
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/linux/of_address.h2
-rw-r--r--include/linux/percpu-rwsem.h4
-rw-r--r--include/linux/pinctrl/pinconf-generic.h5
-rw-r--r--include/linux/pinctrl/pinctrl.h19
-rw-r--r--include/linux/platform_data/ads7828.h29
-rw-r--r--include/linux/platform_data/clk-integrator.h2
-rw-r--r--include/linux/platform_data/omap_ocp2scp.h31
-rw-r--r--include/linux/platform_data/pinctrl-coh901.h4
-rw-r--r--include/linux/platform_data/pinctrl-nomadik.h (renamed from arch/arm/plat-nomadik/include/plat/pincfg.h)111
-rw-r--r--include/linux/platform_data/pxa_sdhci.h6
-rw-r--r--include/linux/rio.h2
-rw-r--r--include/linux/spi/ads7846.h5
-rw-r--r--include/media/adv7604.h21
-rw-r--r--include/net/tcp.h1
-rw-r--r--include/net/xfrm.h2
-rw-r--r--include/scsi/scsi_device.h4
-rw-r--r--include/trace/events/gfpflags.h1
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/hw_breakpoint.h30
-rw-r--r--include/uapi/linux/oom.h9
-rw-r--r--kernel/events/hw_breakpoint.c12
-rw-r--r--kernel/futex.c59
-rw-r--r--kernel/irq/irqdomain.c4
-rw-r--r--kernel/modsign_pubkey.c4
-rw-r--r--kernel/module_signing.c14
-rw-r--r--kernel/sched/auto_group.c4
-rw-r--r--kernel/sched/auto_group.h5
-rw-r--r--kernel/watchdog.c7
-rw-r--r--kernel/workqueue.c22
-rw-r--r--lib/Makefile2
-rw-r--r--lib/asn1_decoder.c2
-rw-r--r--lib/mpi/longlong.h19
-rw-r--r--mm/bootmem.c10
-rw-r--r--mm/compaction.c10
-rw-r--r--mm/dmapool.c31
-rw-r--r--mm/highmem.c2
-rw-r--r--mm/memcontrol.c67
-rw-r--r--mm/memory-failure.c8
-rw-r--r--mm/memory.c10
-rw-r--r--mm/memory_hotplug.c7
-rw-r--r--mm/mempolicy.c22
-rw-r--r--mm/mmap.c2
-rw-r--r--mm/mmzone.c6
-rw-r--r--mm/nobootmem.c3
-rw-r--r--mm/page_alloc.c47
-rw-r--r--mm/shmem.c44
-rw-r--r--mm/sparse.c10
-rw-r--r--mm/swapfile.c4
-rw-r--r--mm/vmscan.c108
-rw-r--r--net/batman-adv/soft-interface.c12
-rw-r--r--net/batman-adv/translation-table.c15
-rw-r--r--net/bluetooth/hci_core.c4
-rw-r--r--net/bluetooth/mgmt.c12
-rw-r--r--net/bluetooth/smp.c2
-rw-r--r--net/can/bcm.c3
-rw-r--r--net/core/dev.c6
-rw-r--r--net/core/dev_addr_lists.c3
-rw-r--r--net/core/net-sysfs.c20
-rw-r--r--net/core/skbuff.c6
-rw-r--r--net/ipv4/icmp.c3
-rw-r--r--net/ipv4/inet_diag.c154
-rw-r--r--net/ipv4/ip_fragment.c19
-rw-r--r--net/ipv4/ip_sockglue.c35
-rw-r--r--net/ipv4/ip_vti.c5
-rw-r--r--net/ipv4/ipmr.c4
-rw-r--r--net/ipv4/route.c9
-rw-r--r--net/ipv4/tcp.c19
-rw-r--r--net/ipv4/tcp_input.c21
-rw-r--r--net/ipv4/tcp_metrics.c12
-rw-r--r--net/ipv4/tcp_output.c19
-rw-r--r--net/ipv4/xfrm4_policy.c13
-rw-r--r--net/ipv6/inet6_connection_sock.c3
-rw-r--r--net/ipv6/ipv6_sockglue.c1
-rw-r--r--net/irda/irttp.c1
-rw-r--r--net/mac80211/cfg.c3
-rw-r--r--net/mac80211/ibss.c8
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/main.c6
-rw-r--r--net/mac80211/offchannel.c2
-rw-r--r--net/mac80211/scan.c2
-rw-r--r--net/mac80211/sta_info.c11
-rw-r--r--net/mac80211/status.c9
-rw-r--r--net/mac80211/tx.c9
-rw-r--r--net/mac80211/util.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c4
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c7
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c7
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c7
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c2
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c3
-rw-r--r--net/nfc/llcp/llcp.c2
-rw-r--r--net/openvswitch/flow.c14
-rw-r--r--net/openvswitch/vport-netdev.c2
-rw-r--r--net/sctp/chunk.c20
-rw-r--r--net/sctp/proc.c8
-rw-r--r--net/sctp/socket.c4
-rw-r--r--net/sctp/transport.c2
-rw-r--r--net/wireless/reg.c5
-rw-r--r--scripts/headers_install.pl3
-rw-r--r--scripts/kconfig/expr.h5
-rw-r--r--scripts/kconfig/list.h91
-rw-r--r--scripts/kconfig/lkc_proto.h4
-rw-r--r--scripts/kconfig/mconf.c6
-rw-r--r--scripts/kconfig/menu.c14
-rwxr-xr-xscripts/sign-file6
-rw-r--r--security/device_cgroup.c18
-rw-r--r--security/selinux/netnode.c3
-rw-r--r--sound/pci/es1968.c11
-rw-r--r--sound/pci/fm801.c11
-rw-r--r--sound/pci/hda/hda_codec.c13
-rw-r--r--sound/pci/hda/hda_codec.h1
-rw-r--r--sound/pci/hda/hda_intel.c39
-rw-r--r--sound/pci/hda/patch_cirrus.c1
-rw-r--r--sound/pci/hda/patch_realtek.c2
-rw-r--r--sound/soc/codecs/arizona.c4
-rw-r--r--sound/soc/codecs/cs4271.c11
-rw-r--r--sound/soc/codecs/cs42l52.c3
-rw-r--r--sound/soc/codecs/wm5102.c552
-rw-r--r--sound/soc/codecs/wm8978.c2
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c3
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c74
-rw-r--r--sound/soc/mxs/mxs-saif.c17
-rw-r--r--sound/soc/samsung/Kconfig2
-rw-r--r--sound/soc/samsung/bells.c2
-rw-r--r--sound/soc/soc-core.c5
-rw-r--r--sound/soc/soc-dapm.c2
-rw-r--r--sound/usb/card.c6
-rw-r--r--sound/usb/midi.c8
-rw-r--r--sound/usb/pcm.c2
-rw-r--r--tools/Makefile24
-rw-r--r--tools/perf/Makefile29
-rw-r--r--tools/perf/arch/x86/include/perf_regs.h2
-rw-r--r--tools/perf/builtin-kvm.c121
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/perf.h16
-rw-r--r--tools/perf/util/evsel.c4
-rw-r--r--tools/perf/util/evsel.h3
-rw-r--r--tools/perf/util/header.c2
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/parse-events-test.c2
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/parse-events.h2
-rw-r--r--tools/perf/util/pmu.h2
-rw-r--r--tools/perf/util/session.h2
-rw-r--r--tools/perf/util/strbuf.c8
-rw-r--r--tools/power/x86/turbostat/turbostat.c28
-rw-r--r--tools/scripts/Makefile.include23
757 files changed, 16935 insertions, 7304 deletions
diff --git a/CREDITS b/CREDITS
index d8fe12a9421f..2346b09ca8bb 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1823,6 +1823,11 @@ S: Kattreinstr 38
S: D-64295
S: Germany
+N: Avi Kivity
+E: avi.kivity@gmail.com
+D: Kernel-based Virtual Machine (KVM)
+S: Ra'annana, Israel
+
N: Andi Kleen
E: andi@firstfloor.org
U: http://www.halobates.de
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt
index 1401cece745a..9bc95942ec22 100644
--- a/Documentation/IRQ-domain.txt
+++ b/Documentation/IRQ-domain.txt
@@ -7,6 +7,21 @@ systems with multiple interrupt controllers the kernel must ensure
that each one gets assigned non-overlapping allocations of Linux
IRQ numbers.
+The number of interrupt controllers registered as unique irqchips
+show a rising tendency: for example subdrivers of different kinds
+such as GPIO controllers avoid reimplementing identical callback
+mechanisms as the IRQ core system by modelling their interrupt
+handlers as irqchips, i.e. in effect cascading interrupt controllers.
+
+Here the interrupt number loose all kind of correspondence to
+hardware interrupt numbers: whereas in the past, IRQ numbers could
+be chosen so they matched the hardware IRQ line into the root
+interrupt controller (i.e. the component actually fireing the
+interrupt line to the CPU) nowadays this number is just a number.
+
+For this reason we need a mechanism to separate controller-local
+interrupt numbers, called hardware irq's, from Linux IRQ numbers.
+
The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of
irq numbers, but they don't provide any support for reverse mapping of
the controller-local IRQ (hwirq) number into the Linux IRQ number
@@ -40,6 +55,10 @@ required hardware setup.
When an interrupt is received, irq_find_mapping() function should
be used to find the Linux IRQ number from the hwirq number.
+The irq_create_mapping() function must be called *atleast once*
+before any call to irq_find_mapping(), lest the descriptor will not
+be allocated.
+
If the driver has the Linux IRQ number or the irq_data pointer, and
needs to know the associated hwirq number (such as in the irq_chip
callbacks) then it can be directly obtained from irq_data->hwirq.
@@ -119,4 +138,17 @@ numbers.
Most users of legacy mappings should use irq_domain_add_simple() which
will use a legacy domain only if an IRQ range is supplied by the
-system and will otherwise use a linear domain mapping.
+system and will otherwise use a linear domain mapping. The semantics
+of this call are such that if an IRQ range is specified then
+descriptors will be allocated on-the-fly for it, and if no range is
+specified it will fall through to irq_domain_add_linear() which meand
+*no* irq descriptors will be allocated.
+
+A typical use case for simple domains is where an irqchip provider
+is supporting both dynamic and static IRQ assignments.
+
+In order to avoid ending up in a situation where a linear domain is
+used and no descriptor gets allocated it is very important to make sure
+that the driver using the simple domain call irq_create_mapping()
+before any irq_find_mapping() since the latter will actually work
+for the static IRQ assignment case.
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index c07f7b4fb88d..71c4da413444 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -466,6 +466,10 @@ Note:
5.3 swappiness
Similar to /proc/sys/vm/swappiness, but affecting a hierarchy of groups only.
+Please note that unlike the global swappiness, memcg knob set to 0
+really prevents from any swapping even if there is a swap storage
+available. This might lead to memcg OOM killer if there are no file
+pages to reclaim.
Following cgroups' swappiness can't be changed.
- root cgroup (uses /proc/sys/vm/swappiness).
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index d187e9f7cf1c..1196290082d1 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -7,6 +7,12 @@ PIT Timer required properties:
- interrupts: Should contain interrupt for the PIT which is the IRQ line
shared across all System Controller members.
+System Timer (ST) required properties:
+- compatible: Should be "atmel,at91rm9200-st"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt for the ST which is the IRQ line
+ shared across all System Controller members.
+
TC/TCLIB Timer required properties:
- compatible: Should be "atmel,<chip>-tcb".
<chip> can be "at91rm9200" or "at91sam9x5"
diff --git a/Documentation/devicetree/bindings/clock/imx23-clock.txt b/Documentation/devicetree/bindings/clock/imx23-clock.txt
index a0b867ef8d96..baadbb11fe98 100644
--- a/Documentation/devicetree/bindings/clock/imx23-clock.txt
+++ b/Documentation/devicetree/bindings/clock/imx23-clock.txt
@@ -52,7 +52,7 @@ clocks and IDs.
lcdif 38
etm 39
usb 40
- usb_pwr 41
+ usb_phy 41
Examples:
diff --git a/Documentation/devicetree/bindings/clock/imx28-clock.txt b/Documentation/devicetree/bindings/clock/imx28-clock.txt
index aa2af2866fe8..52a49a4a50b3 100644
--- a/Documentation/devicetree/bindings/clock/imx28-clock.txt
+++ b/Documentation/devicetree/bindings/clock/imx28-clock.txt
@@ -73,8 +73,8 @@ clocks and IDs.
can1 59
usb0 60
usb1 61
- usb0_pwr 62
- usb1_pwr 63
+ usb0_phy 62
+ usb1_phy 63
enet_out 64
Examples:
diff --git a/Documentation/devicetree/bindings/gpio/gpio.txt b/Documentation/devicetree/bindings/gpio/gpio.txt
index 4e16ba4feab0..a33628759d36 100644
--- a/Documentation/devicetree/bindings/gpio/gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio.txt
@@ -75,4 +75,40 @@ Example of two SOC GPIO banks defined as gpio-controller nodes:
gpio-controller;
};
+2.1) gpio-controller and pinctrl subsystem
+------------------------------------------
+gpio-controller on a SOC might be tightly coupled with the pinctrl
+subsystem, in the sense that the pins can be used by other functions
+together with optional gpio feature.
+
+While the pin allocation is totally managed by the pin ctrl subsystem,
+gpio (under gpiolib) is still maintained by gpio drivers. It may happen
+that different pin ranges in a SoC is managed by different gpio drivers.
+
+This makes it logical to let gpio drivers announce their pin ranges to
+the pin ctrl subsystem and call 'pinctrl_request_gpio' in order to
+request the corresponding pin before any gpio usage.
+
+For this, the gpio controller can use a pinctrl phandle and pins to
+announce the pinrange to the pin ctrl subsystem. For example,
+
+ qe_pio_e: gpio-controller@1460 {
+ #gpio-cells = <2>;
+ compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+ reg = <0x1460 0x18>;
+ gpio-controller;
+ gpio-ranges = <&pinctrl1 20 10>, <&pinctrl2 50 20>;
+
+ }
+
+where,
+ &pinctrl1 and &pinctrl2 is the phandle to the pinctrl DT node.
+
+ 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.
+
+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/gpio/gpio_atmel.txt b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
index 66efc804806a..85f8c0d084fa 100644
--- a/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio_atmel.txt
@@ -9,6 +9,10 @@ Required properties:
unused).
- gpio-controller: Marks the device node as a GPIO controller.
+optional properties:
+- #gpio-lines: Number of gpio if absent 32.
+
+
Example:
pioA: gpio@fffff200 {
compatible = "atmel,at91rm9200-gpio";
@@ -16,5 +20,6 @@ Example:
interrupts = <2 4>;
#gpio-cells = <2>;
gpio-controller;
+ #gpio-lines = <19>;
};
diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 8e2e0ba2f486..a591c6741d75 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -21,6 +21,12 @@ Optional properties:
- cd-inverted: when present, polarity on the cd gpio line is inverted
- wp-inverted: when present, polarity on the wp gpio line is inverted
- max-frequency: maximum operating clock frequency
+- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
+ this system, even if the controller claims it is.
+
+Optional SDIO properties:
+- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
+- enable-sdio-wakeup: Enables wake up of host system on SDIO IRQ assertion
Example:
@@ -33,4 +39,6 @@ sdhci@ab000000 {
cd-inverted;
wp-gpios = <&gpio 70 0>;
max-frequency = <50000000>;
+ keep-power-in-suspend;
+ enable-sdio-wakeup;
}
diff --git a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
index 630a7d7f4718..97e9e315400d 100644
--- a/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
+++ b/Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
@@ -12,10 +12,6 @@ is used. The Samsung's SDHCI controller bindings extends this as listed below.
[A] The property "samsung,cd-pinmux-gpio" can be used as stated in the
"Optional Board Specific Properties" section below.
-[B] If core card-detect bindings and "samsung,cd-pinmux-gpio" property
- is not specified, it is assumed that there is no card detection
- mechanism used.
-
Required SoC Specific Properties:
- compatible: should be one of the following
- "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
@@ -24,14 +20,18 @@ Required SoC Specific Properties:
controller.
Required Board Specific Properties:
-- gpios: Should specify the gpios used for clock, command and data lines. The
- gpio specifier format depends on the gpio controller.
+- Samsung GPIO variant (will be completely replaced by pinctrl):
+ - gpios: Should specify the gpios used for clock, command and data lines. The
+ gpio specifier format depends on the gpio controller.
+- Pinctrl variant (preferred if available):
+ - pinctrl-0: Should specify pin control groups used for this controller.
+ - pinctrl-names: Should contain only one value - "default".
Optional Board Specific Properties:
- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed
through a pinmux to the card-detect pin of the card slot. This property
should be used only if none of the mmc core card-detect properties are
- used.
+ used. Only for Samsung GPIO variant.
Example:
sdhci@12530000 {
@@ -40,12 +40,18 @@ Example:
interrupts = <0 75 0>;
bus-width = <4>;
cd-gpios = <&gpk2 2 2 3 3>;
+
+ /* Samsung GPIO variant */
gpios = <&gpk2 0 2 0 3>, /* clock line */
<&gpk2 1 2 0 3>, /* command line */
<&gpk2 3 2 3 3>, /* data line 0 */
<&gpk2 4 2 3 3>, /* data line 1 */
<&gpk2 5 2 3 3>, /* data line 2 */
<&gpk2 6 2 3 3>; /* data line 3 */
+
+ /* Pinctrl variant */
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
+ pinctrl-names = "default";
};
Note: This example shows both SoC specific and board specific properties
diff --git a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
index 06cd32d08052..06cd32d08052 100644
--- a/Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
diff --git a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
index be76a23b34c4..ed271fc255b2 100644
--- a/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
+++ b/Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
@@ -19,6 +19,7 @@ ti,dual-volt: boolean, supports dual voltage cards
"supply-name" examples are "vmmc", "vmmc_aux" etc
ti,non-removable: non-removable slot (like eMMC)
ti,needs-special-reset: Requires a special softreset sequence
+ti,needs-special-hs-handling: HSMMC IP needs special setting for handling High Speed
Example:
mmc1: mmc@0x4809c000 {
diff --git a/Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt b/Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt
new file mode 100644
index 000000000000..d7fb6abb3eb8
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt
@@ -0,0 +1,23 @@
+* Wondermedia WM8505/WM8650 SD/MMC Host Controller
+
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the wmt-sdmmc driver.
+
+Required properties:
+- compatible: Should be "wm,wm8505-sdhc".
+- interrupts: Two interrupts are required - regular irq and dma irq.
+
+Optional properties:
+- sdon-inverted: SD_ON bit is inverted on the controller
+
+Examples:
+
+sdhc@d800a000 {
+ compatible = "wm,wm8505-sdhc";
+ reg = <0xd800a000 0x1000>;
+ interrupts = <20 21>;
+ clocks = <&sdhc>;
+ bus-width = <4>;
+ sdon-inverted;
+};
+
diff --git a/Documentation/devicetree/bindings/net/mdio-gpio.txt b/Documentation/devicetree/bindings/net/mdio-gpio.txt
index bc9549529014..c79bab025369 100644
--- a/Documentation/devicetree/bindings/net/mdio-gpio.txt
+++ b/Documentation/devicetree/bindings/net/mdio-gpio.txt
@@ -8,9 +8,16 @@ gpios property as described in section VIII.1 in the following order:
MDC, MDIO.
+Note: Each gpio-mdio bus should have an alias correctly numbered in "aliases"
+node.
+
Example:
-mdio {
+aliases {
+ mdio-gpio0 = <&mdio0>;
+};
+
+mdio0: mdio {
compatible = "virtual,mdio-gpio";
#address-cells = <1>;
#size-cells = <0>;
diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
new file mode 100644
index 000000000000..3a268127b054
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt
@@ -0,0 +1,141 @@
+* Atmel AT91 Pinmux Controller
+
+The AT91 Pinmux Controler, 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
+different PAD settings (like pull up, keeper, etc) the contoller controls
+also the PAD settings parameters.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+Atmel AT91 pin configuration node is a node of a group of pins which can be
+used for a specific device or function. This node represents both mux and config
+of the pins in that group. The 'pins' selects the function mode(also named pin
+mode) this pin can work on and the 'config' configures various pad settings
+such as pull-up, multi drive, etc.
+
+Required properties for iomux controller:
+- compatible: "atmel,at91rm9200-pinctrl"
+- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be
+ configured in this periph mode. All the periph and bank need to be describe.
+
+How to create such array:
+
+Each column will represent the possible peripheral of the pinctrl
+Each line will represent a pio bank
+
+Take an example on the 9260
+Peripheral: 2 ( A and B)
+Bank: 3 (A, B and C)
+=>
+
+ /* A B */
+ 0xffffffff 0xffc00c3b /* pioA */
+ 0xffffffff 0x7fff3ccf /* pioB */
+ 0xffffffff 0x007fffff /* pioC */
+
+For each peripheral/bank we will descibe in a u32 if a pin can can be
+configured in it by putting 1 to the pin bit (1 << pin)
+
+Let's take the pioA on peripheral B
+From the datasheet Table 10-2.
+Peripheral B
+PA0 MCDB0
+PA1 MCCDB
+PA2
+PA3 MCDB3
+PA4 MCDB2
+PA5 MCDB1
+PA6
+PA7
+PA8
+PA9
+PA10 ETX2
+PA11 ETX3
+PA12
+PA13
+PA14
+PA15
+PA16
+PA17
+PA18
+PA19
+PA20
+PA21
+PA22 ETXER
+PA23 ETX2
+PA24 ETX3
+PA25 ERX2
+PA26 ERX3
+PA27 ERXCK
+PA28 ECRS
+PA29 ECOL
+PA30 RXD4
+PA31 TXD4
+
+=> 0xffc00c3b
+
+Required properties for pin configuration node:
+- atmel,pins: 4 integers array, represents a group of pins mux and config
+ setting. The format is atmel,pins = <PIN_BANK PIN_BANK_NUM PERIPH CONFIG>.
+ The PERIPH 0 means gpio.
+
+Bits used for CONFIG:
+PULL_UP (1 << 0): indicate this pin need a pull up.
+MULTIDRIVE (1 << 1): indicate this pin need to be configured as multidrive.
+DEGLITCH (1 << 2): indicate this pin need deglitch.
+PULL_DOWN (1 << 3): indicate this pin need a pull down.
+DIS_SCHMIT (1 << 4): indicate this pin need to disable schmit trigger.
+DEBOUNCE (1 << 16): indicate this pin need debounce.
+DEBOUNCE_VAL (0x3fff << 17): debounce val.
+
+NOTE:
+Some requirements for using atmel,at91rm9200-pinctrl binding:
+1. We have pin function node defined under at91 controller node to represent
+ what pinmux functions this SoC supports.
+2. The driver can use the function node's name and pin configuration node's
+ name describe the pin function and group hierarchy.
+ For example, Linux at91 pinctrl driver takes the function node's name
+ as the function name and pin configuration node's name as group name to
+ create the map table.
+3. Each pin configuration node should have a phandle, devices can set pins
+ configurations by referring to the phandle of that pin configuration node.
+4. The gpio controller must be describe in the pinctrl simple-bus.
+
+Examples:
+
+pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ reg = <0xfffff400 0x600>;
+
+ atmel,mux-mask = <
+ /* A B */
+ 0xffffffff 0xffc00c3b /* pioA */
+ 0xffffffff 0x7fff3ccf /* pioB */
+ 0xffffffff 0x007fffff /* pioC */
+ >;
+
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <1 14 0x1 0x0 /* PB14 periph A */
+ 1 15 0x1 0x1>; /* PB15 periph with pullup */
+ };
+ };
+};
+
+dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+};
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index a1793d670cd0..3844d21d6ca3 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -33,7 +33,7 @@ Table of Contents
2 Modifying System Parameters
3 Per-Process Parameters
- 3.1 /proc/<pid>/oom_score_adj - Adjust the oom-killer
+ 3.1 /proc/<pid>/oom_adj & /proc/<pid>/oom_score_adj - Adjust the oom-killer
score
3.2 /proc/<pid>/oom_score - Display current oom-killer score
3.3 /proc/<pid>/io - Display the IO accounting fields
@@ -1320,10 +1320,10 @@ of the kernel.
CHAPTER 3: PER-PROCESS PARAMETERS
------------------------------------------------------------------------------
-3.1 /proc/<pid>/oom_score_adj- Adjust the oom-killer score
+3.1 /proc/<pid>/oom_adj & /proc/<pid>/oom_score_adj- Adjust the oom-killer score
--------------------------------------------------------------------------------
-This file can be used to adjust the badness heuristic used to select which
+These file can be used to adjust the badness heuristic used to select which
process gets killed in out of memory conditions.
The badness heuristic assigns a value to each candidate task ranging from 0
@@ -1361,6 +1361,12 @@ same system, cpuset, mempolicy, or memory controller resources to use at least
equivalent to discounting 50% of the task's allowed memory from being considered
as scoring against the task.
+For backwards compatibility with previous kernels, /proc/<pid>/oom_adj may also
+be used to tune the badness score. Its acceptable values range from -16
+(OOM_ADJUST_MIN) to +15 (OOM_ADJUST_MAX) and a special value of -17
+(OOM_DISABLE) to disable oom killing entirely for that task. Its value is
+scaled linearly with /proc/<pid>/oom_score_adj.
+
The value of /proc/<pid>/oom_score_adj may be reduced no lower than the last
value set by a CAP_SYS_RESOURCE process. To reduce the value any lower
requires CAP_SYS_RESOURCE.
@@ -1375,7 +1381,9 @@ minimal amount of work.
-------------------------------------------------------------
This file can be used to check the current score used by the oom-killer is for
-any given <pid>.
+any given <pid>. Use it together with /proc/<pid>/oom_score_adj to tune which
+process should be killed in an out-of-memory situation.
+
3.3 /proc/<pid>/io - Display the IO accounting fields
-------------------------------------------------------
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index e08a883de36e..77a1d11af723 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -439,6 +439,48 @@ slower clock delays the rising edge of SCK, and the I2C master adjusts its
signaling rate accordingly.
+GPIO controllers and the pinctrl subsystem
+------------------------------------------
+
+A GPIO controller on a SOC might be tightly coupled with the pinctrl
+subsystem, in the sense that the pins can be used by other functions
+together with an optional gpio feature. We have already covered the
+case where e.g. a GPIO controller need to reserve a pin or set the
+direction of a pin by calling any of:
+
+pinctrl_request_gpio()
+pinctrl_free_gpio()
+pinctrl_gpio_direction_input()
+pinctrl_gpio_direction_output()
+
+But how does the pin control subsystem cross-correlate the GPIO
+numbers (which are a global business) to a certain pin on a certain
+pin controller?
+
+This is done by registering "ranges" of pins, which are essentially
+cross-reference tables. These are described in
+Documentation/pinctrl.txt
+
+While the pin allocation is totally managed by the pinctrl subsystem,
+gpio (under gpiolib) is still maintained by gpio drivers. It may happen
+that different pin ranges in a SoC is managed by different gpio drivers.
+
+This makes it logical to let gpio drivers announce their pin ranges to
+the pin ctrl subsystem before it will call 'pinctrl_request_gpio' in order
+to request the corresponding pin to be prepared by the pinctrl subsystem
+before any gpio usage.
+
+For this, the gpio controller can register its pin range with pinctrl
+subsystem. There are two ways of doing it currently: with or without DT.
+
+For with DT support refer to Documentation/devicetree/bindings/gpio/gpio.txt.
+
+For non-DT support, user can call gpiochip_add_pin_range() with appropriate
+parameters to register a range of gpio pins with a pinctrl driver. For this
+exact name string of pinctrl device has to be passed as one of the
+argument to this routine.
+
+
What do these conventions omit?
===============================
One of the biggest things these conventions omit is pin multiplexing, since
diff --git a/Documentation/hwmon/ads7828 b/Documentation/hwmon/ads7828
index 2bbebe6f771f..f6e263e0f607 100644
--- a/Documentation/hwmon/ads7828
+++ b/Documentation/hwmon/ads7828
@@ -4,29 +4,47 @@ Kernel driver ads7828
Supported chips:
* Texas Instruments/Burr-Brown ADS7828
Prefix: 'ads7828'
- Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4b
- Datasheet: Publicly available at the Texas Instruments website :
+ Datasheet: Publicly available at the Texas Instruments website:
http://focus.ti.com/lit/ds/symlink/ads7828.pdf
+ * Texas Instruments ADS7830
+ Prefix: 'ads7830'
+ Datasheet: Publicly available at the Texas Instruments website:
+ http://focus.ti.com/lit/ds/symlink/ads7830.pdf
+
Authors:
Steve Hardy <shardy@redhat.com>
+ Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+
+Platform data
+-------------
+
+The ads7828 driver accepts an optional ads7828_platform_data structure (defined
+in include/linux/platform_data/ads7828.h). The structure fields are:
-Module Parameters
------------------
+* diff_input: (bool) Differential operation
+ set to true for differential mode, false for default single ended mode.
-* se_input: bool (default Y)
- Single ended operation - set to N for differential mode
-* int_vref: bool (default Y)
- Operate with the internal 2.5V reference - set to N for external reference
-* vref_mv: int (default 2500)
- If using an external reference, set this to the reference voltage in mV
+* ext_vref: (bool) External reference
+ set to true if it operates with an external reference, false for default
+ internal reference.
+
+* vref_mv: (unsigned int) Voltage reference
+ if using an external reference, set this to the reference voltage in mV,
+ otherwise it will default to the internal value (2500mV). This value will be
+ bounded with limits accepted by the chip, described in the datasheet.
+
+ If no structure is provided, the configuration defaults to single ended
+ operation and internal voltage reference (2.5V).
Description
-----------
-This driver implements support for the Texas Instruments ADS7828.
+This driver implements support for the Texas Instruments ADS7828 and ADS7830.
-This device is a 12-bit 8-channel A-D converter.
+The ADS7828 device is a 12-bit 8-channel A/D converter, while the ADS7830 does
+8-bit sampling.
It can operate in single ended mode (8 +ve inputs) or in differential mode,
where 4 differential pairs can be measured.
@@ -34,3 +52,7 @@ where 4 differential pairs can be measured.
The chip also has the facility to use an external voltage reference. This
may be required if your hardware supplies the ADS7828 from a 5V supply, see
the datasheet for more details.
+
+There is no reliable way to identify this chip, so the driver will not scan
+some addresses to try to auto-detect it. That means that you will have to
+statically declare the device in the platform support code.
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index f17256f069ba..3374c085678d 100644
--- a/Documentation/hwmon/coretemp
+++ b/Documentation/hwmon/coretemp
@@ -98,8 +98,10 @@ Process Processor TjMax(C)
45nm Atom Processors
D525/510/425/410 100
+ Z670/650 90
Z560/550/540/530P/530/520PT/520/515/510PT/510P 90
Z510/500 90
+ N570/550 100
N475/470/455/450 100
N280/270 90
330/230 125
diff --git a/Documentation/hwmon/da9055 b/Documentation/hwmon/da9055
new file mode 100644
index 000000000000..855c3f536e00
--- /dev/null
+++ b/Documentation/hwmon/da9055
@@ -0,0 +1,47 @@
+Supported chips:
+ * Dialog Semiconductors DA9055 PMIC
+ Prefix: 'da9055'
+ Datasheet: Datasheet is not publicly available.
+
+Authors: David Dajun Chen <dchen@diasemi.com>
+
+Description
+-----------
+
+The DA9055 provides an Analogue to Digital Converter (ADC) with 10 bits
+resolution and track and hold circuitry combined with an analogue input
+multiplexer. The analogue input multiplexer will allow conversion of up to 5
+different inputs. The track and hold circuit ensures stable input voltages at
+the input of the ADC during the conversion.
+
+The ADC is used to measure the following inputs:
+Channel 0: VDDOUT - measurement of the system voltage
+Channel 1: ADC_IN1 - high impedance input (0 - 2.5V)
+Channel 2: ADC_IN2 - high impedance input (0 - 2.5V)
+Channel 3: ADC_IN3 - high impedance input (0 - 2.5V)
+Channel 4: Internal Tjunc. - sense (internal temp. sensor)
+
+By using sysfs attributes we can measure the system voltage VDDOUT,
+chip junction temperature and auxiliary channels voltages.
+
+Voltage Monitoring
+------------------
+
+Voltages are sampled in a AUTO mode it can be manually sampled too and results
+are stored in a 10 bit ADC.
+
+The system voltage is calculated as:
+ Milli volt = ((ADC value * 1000) / 85) + 2500
+
+The voltages on ADC channels 1, 2 and 3 are calculated as:
+ Milli volt = (ADC value * 1000) / 102
+
+Temperature Monitoring
+----------------------
+
+Temperatures are sampled by a 10 bit ADC. Junction temperatures
+are monitored by the ADC channels.
+
+The junction temperature is calculated:
+ Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332
+The junction temperature attribute is supported by the driver.
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index 22ae8441489f..0d98fac8893b 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -25,6 +25,8 @@ All attributes are read-only.
serial Product Serial Number (from CID Register)
erase_size Erase group size
preferred_erase_size Preferred erase size
+ raw_rpmb_size_mult RPMB partition size
+ rel_sectors Reliable write sector count
Note on Erase Size and Preferred Erase Size:
@@ -65,6 +67,11 @@ Note on Erase Size and Preferred Erase Size:
"preferred_erase_size" is in bytes.
+Note on raw_rpmb_size_mult:
+ "raw_rpmb_size_mult" is a mutliple of 128kB block.
+ RPMB size in byte is calculated by using the following equation:
+ RPMB partition size = 128kB x raw_rpmb_size_mult
+
SD/MMC/SDIO Clock Gating Attribute
==================================
diff --git a/Documentation/networking/netdev-features.txt b/Documentation/networking/netdev-features.txt
index 4164f5c02e4b..f310edec8a77 100644
--- a/Documentation/networking/netdev-features.txt
+++ b/Documentation/networking/netdev-features.txt
@@ -164,4 +164,4 @@ read the CRC recorded by the NIC on receipt of the packet.
This requests that the NIC receive all possible frames, including errored
frames (such as bad FCS, etc). This can be helpful when sniffing a link with
bad packets on it. Some NICs may receive more packets if also put into normal
-PROMISC mdoe.
+PROMISC mode.
diff --git a/Documentation/networking/vxlan.txt b/Documentation/networking/vxlan.txt
index 5b34b762d7d5..6d993510f091 100644
--- a/Documentation/networking/vxlan.txt
+++ b/Documentation/networking/vxlan.txt
@@ -32,7 +32,7 @@ no entry is in the forwarding table.
# ip link delete vxlan0
3. Show vxlan info
- # ip -d show vxlan0
+ # ip -d link show vxlan0
It is possible to create, destroy and display the vxlan
forwarding table using the new bridge command.
@@ -41,7 +41,7 @@ forwarding table using the new bridge command.
# bridge fdb add to 00:17:42:8a:b4:05 dst 192.19.0.2 dev vxlan0
2. Delete forwarding table entry
- # bridge fdb delete 00:17:42:8a:b4:05
+ # bridge fdb delete 00:17:42:8a:b4:05 dev vxlan0
3. Show forwarding table
# bridge fdb show dev vxlan0
diff --git a/Documentation/pinctrl.txt b/Documentation/pinctrl.txt
index 3b4ee5328868..da40efbef6ec 100644
--- a/Documentation/pinctrl.txt
+++ b/Documentation/pinctrl.txt
@@ -364,6 +364,9 @@ will get an pin number into its handled number range. Further it is also passed
the range ID value, so that the pin controller knows which range it should
deal with.
+Calling pinctrl_add_gpio_range from pinctrl driver is DEPRECATED. Please see
+section 2.1 of Documentation/devicetree/bindings/gpio/gpio.txt on how to bind
+pinctrl and gpio drivers.
PINMUX interfaces
=================
@@ -1193,4 +1196,6 @@ foo_switch()
...
}
-The above has to be done from process context.
+The above has to be done from process context. The reservation of the pins
+will be done when the state is activated, so in effect one specific pin
+can be used by different functions at different times on a running system.
diff --git a/MAINTAINERS b/MAINTAINERS
index 59203e77ce9e..cf7ff78f019b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -526,17 +526,17 @@ F: drivers/video/geode/
F: arch/x86/include/asm/geode.h
AMD IOMMU (AMD-VI)
-M: Joerg Roedel <joerg.roedel@amd.com>
+M: Joerg Roedel <joro@8bytes.org>
L: iommu@lists.linux-foundation.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
-S: Supported
+S: Maintained
F: drivers/iommu/amd_iommu*.[ch]
F: include/linux/amd-iommu.h
AMD MICROCODE UPDATE SUPPORT
-M: Andreas Herrmann <andreas.herrmann3@amd.com>
+M: Andreas Herrmann <herrmann.der.user@googlemail.com>
L: amd64-microcode@amd64.org
-S: Supported
+S: Maintained
F: arch/x86/kernel/microcode_amd.c
AMS (Apple Motion Sensor) DRIVER
@@ -841,6 +841,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/kristoffer/linux-hpc.git
F: arch/arm/mach-sa1100/jornada720.c
F: arch/arm/mach-sa1100/include/mach/jornada720.h
+ARM/IGEP MACHINE SUPPORT
+M: Enric Balletbo i Serra <eballetbo@gmail.com>
+M: Javier Martinez Canillas <javier@dowhile0.org>
+L: linux-omap@vger.kernel.org
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/mach-omap2/board-igep0020.c
+
ARM/INCOME PXA270 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1229,6 +1237,7 @@ F: drivers/video/wm8505fb*
F: drivers/video/wmt_ge_rops.*
F: drivers/tty/serial/vt8500_serial.c
F: drivers/rtc/rtc-vt8500-c
+F: drivers/mmc/host/wmt-sdmmc.c
ARM/ZIPIT Z2 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
@@ -1360,14 +1369,6 @@ S: Maintained
F: drivers/atm/
F: include/linux/atm*
-ATMEL AT91 MCI DRIVER
-M: Ludovic Desroches <ludovic.desroches@atmel.com>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W: http://www.atmel.com/products/AT91/
-W: http://www.at91.com/
-S: Maintained
-F: drivers/mmc/host/at91_mci.c
-
ATMEL AT91 / AT32 MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Maintained
@@ -1986,7 +1987,6 @@ F: fs/coda/
F: include/linux/coda*.h
COMMON CLK FRAMEWORK
-M: Mike Turquette <mturquette@ti.com>
M: Mike Turquette <mturquette@linaro.org>
L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
T: git git://git.linaro.org/people/mturquette/linux.git
@@ -2708,10 +2708,10 @@ F: include/linux/edac.h
EDAC-AMD64
M: Doug Thompson <dougthompson@xmission.com>
-M: Borislav Petkov <borislav.petkov@amd.com>
+M: Borislav Petkov <bp@alien8.de>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
-S: Supported
+S: Maintained
F: drivers/edac/amd64_edac*
EDAC-E752X
@@ -3598,6 +3598,49 @@ F: drivers/hid/hid-hyperv.c
F: drivers/net/hyperv/
F: drivers/staging/hv/
+I2C OVER PARALLEL PORT
+M: Jean Delvare <khali@linux-fr.org>
+L: linux-i2c@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-parport
+F: Documentation/i2c/busses/i2c-parport-light
+F: drivers/i2c/busses/i2c-parport.c
+F: drivers/i2c/busses/i2c-parport-light.c
+
+I2C/SMBUS CONTROLLER DRIVERS FOR PC
+M: Jean Delvare <khali@linux-fr.org>
+L: linux-i2c@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-ali1535
+F: Documentation/i2c/busses/i2c-ali1563
+F: Documentation/i2c/busses/i2c-ali15x3
+F: Documentation/i2c/busses/i2c-amd756
+F: Documentation/i2c/busses/i2c-amd8111
+F: Documentation/i2c/busses/i2c-i801
+F: Documentation/i2c/busses/i2c-nforce2
+F: Documentation/i2c/busses/i2c-piix4
+F: Documentation/i2c/busses/i2c-sis5595
+F: Documentation/i2c/busses/i2c-sis630
+F: Documentation/i2c/busses/i2c-sis96x
+F: Documentation/i2c/busses/i2c-via
+F: Documentation/i2c/busses/i2c-viapro
+F: drivers/i2c/busses/i2c-ali1535.c
+F: drivers/i2c/busses/i2c-ali1563.c
+F: drivers/i2c/busses/i2c-ali15x3.c
+F: drivers/i2c/busses/i2c-amd756.c
+F: drivers/i2c/busses/i2c-amd756-s4882.c
+F: drivers/i2c/busses/i2c-amd8111.c
+F: drivers/i2c/busses/i2c-i801.c
+F: drivers/i2c/busses/i2c-isch.c
+F: drivers/i2c/busses/i2c-nforce2.c
+F: drivers/i2c/busses/i2c-nforce2-s4985.c
+F: drivers/i2c/busses/i2c-piix4.c
+F: drivers/i2c/busses/i2c-sis5595.c
+F: drivers/i2c/busses/i2c-sis630.c
+F: drivers/i2c/busses/i2c-sis96x.c
+F: drivers/i2c/busses/i2c-via.c
+F: drivers/i2c/busses/i2c-viapro.c
+
I2C/SMBUS STUB DRIVER
M: "Mark M. Hoffman" <mhoffman@lightlink.com>
L: linux-i2c@vger.kernel.org
@@ -3605,9 +3648,8 @@ S: Maintained
F: drivers/i2c/busses/i2c-stub.c
I2C SUBSYSTEM
-M: "Jean Delvare (PC drivers, core)" <khali@linux-fr.org>
+M: Wolfram Sang <w.sang@pengutronix.de>
M: "Ben Dooks (embedded platforms)" <ben-linux@fluff.org>
-M: "Wolfram Sang (embedded platforms)" <w.sang@pengutronix.de>
L: linux-i2c@vger.kernel.org
W: http://i2c.wiki.kernel.org/
T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-i2c/
@@ -3618,6 +3660,13 @@ F: drivers/i2c/
F: include/linux/i2c.h
F: include/linux/i2c-*.h
+I2C-TAOS-EVM DRIVER
+M: Jean Delvare <khali@linux-fr.org>
+L: linux-i2c@vger.kernel.org
+S: Maintained
+F: Documentation/i2c/busses/i2c-taos-evm
+F: drivers/i2c/busses/i2c-taos-evm.c
+
I2C-TINY-USB DRIVER
M: Till Harbaum <till@harbaum.org>
L: linux-i2c@vger.kernel.org
@@ -3704,7 +3753,7 @@ S: Maintained
F: drivers/platform/x86/ideapad-laptop.c
IDE/ATAPI DRIVERS
-M: Borislav Petkov <petkovbb@gmail.com>
+M: Borislav Petkov <bp@alien8.de>
L: linux-ide@vger.kernel.org
S: Maintained
F: Documentation/cdrom/ide-cd
@@ -4231,8 +4280,8 @@ F: include/linux/lockd/
F: include/linux/sunrpc/
KERNEL VIRTUAL MACHINE (KVM)
-M: Avi Kivity <avi@redhat.com>
M: Marcelo Tosatti <mtosatti@redhat.com>
+M: Gleb Natapov <gleb@redhat.com>
L: kvm@vger.kernel.org
W: http://kvm.qumranet.com
S: Supported
@@ -5364,7 +5413,7 @@ S: Maintained
F: sound/drivers/opl4/
OPROFILE
-M: Robert Richter <robert.richter@amd.com>
+M: Robert Richter <rric@kernel.org>
L: oprofile-list@lists.sf.net
S: Maintained
F: arch/*/include/asm/oprofile*.h
@@ -5639,6 +5688,12 @@ S: Maintained
F: drivers/pinctrl/
F: include/linux/pinctrl/
+PIN CONTROLLER - ATMEL AT91
+M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: drivers/pinctrl/pinctrl-at91.c
+
PIN CONTROLLER - ST SPEAR
M: Viresh Kumar <viresh.linux@gmail.com>
L: spear-devel@list.st.com
@@ -7210,6 +7265,14 @@ L: linux-xtensa@linux-xtensa.org
S: Maintained
F: arch/xtensa/
+THERMAL
+M: Zhang Rui <rui.zhang@intel.com>
+L: linux-pm@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux.git
+S: Supported
+F: drivers/thermal/
+F: include/linux/thermal.h
+
THINKPAD ACPI EXTRAS DRIVER
M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
L: ibm-acpi-devel@lists.sourceforge.net
@@ -7887,13 +7950,6 @@ M: Roger Luethi <rl@hellgate.ch>
S: Maintained
F: drivers/net/ethernet/via/via-rhine.c
-VIAPRO SMBUS DRIVER
-M: Jean Delvare <khali@linux-fr.org>
-L: linux-i2c@vger.kernel.org
-S: Maintained
-F: Documentation/i2c/busses/i2c-viapro
-F: drivers/i2c/busses/i2c-viapro.c
-
VIA SD/MMC CARD CONTROLLER DRIVER
M: Bruce Chang <brucechang@via.com.tw>
M: Harald Welte <HaraldWelte@viatech.com>
@@ -8148,7 +8204,7 @@ F: drivers/platform/x86
X86 MCE INFRASTRUCTURE
M: Tony Luck <tony.luck@intel.com>
-M: Borislav Petkov <bp@amd64.org>
+M: Borislav Petkov <bp@alien8.de>
L: linux-edac@vger.kernel.org
S: Maintained
F: arch/x86/kernel/cpu/mcheck/*
diff --git a/Makefile b/Makefile
index 6edac73ee1ba..540f7b240c77 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 7
SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION =
NAME = Terrified Chipmunk
# *DOCUMENTATION*
@@ -1321,10 +1321,12 @@ kernelversion:
# Clear a bunch of variables before executing the submake
tools/: FORCE
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/
+ $(Q)mkdir -p $(objtree)/tools
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/
tools/%: FORCE
- $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/ $*
+ $(Q)mkdir -p $(objtree)/tools
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= O=$(objtree) subdir=tools -C $(src)/tools/ $*
# Single targets
# ---------------------------------------------------------------------------
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 1e6956a90608..14db93e4c8a8 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -445,7 +445,7 @@ struct procfs_args {
* unhappy with OSF UFS. [CHECKME]
*/
static int
-osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
+osf_ufs_mount(const char *dirname, struct ufs_args __user *args, int flags)
{
int retval;
struct cdfs_args tmp;
@@ -465,7 +465,7 @@ osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags)
}
static int
-osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
+osf_cdfs_mount(const char *dirname, struct cdfs_args __user *args, int flags)
{
int retval;
struct cdfs_args tmp;
@@ -485,7 +485,7 @@ osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags)
}
static int
-osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags)
+osf_procfs_mount(const char *dirname, struct procfs_args __user *args, int flags)
{
struct procfs_args tmp;
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ade7e924bef5..67f1fdbad7f9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -330,6 +330,8 @@ config ARCH_AT91
select IRQ_DOMAIN
select NEED_MACH_GPIO_H
select NEED_MACH_IO_H if PCCARD
+ select PINCTRL
+ select PINCTRL_AT91 if USE_OF
help
This enables support for systems based on Atmel
AT91RM9200 and AT91SAM9* processors.
@@ -547,6 +549,7 @@ config ARCH_KIRKWOOD
select CPU_FEROCEON
select GENERIC_CLOCKEVENTS
select PCI
+ select PCI_QUIRKS
select PLAT_ORION_LEGACY
help
Support for the following Marvell Kirkwood series SoCs:
@@ -586,6 +589,7 @@ config ARCH_MMP
select GPIO_PXA
select IRQ_DOMAIN
select NEED_MACH_GPIO_H
+ select PINCTRL
select PLAT_PXA
select SPARSE_IRQ
help
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 801b92ca0631..abfce280f57b 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -31,7 +31,7 @@ ifeq ($(CONFIG_XIP_KERNEL),y)
$(obj)/xipImage: vmlinux FORCE
$(call if_changed,objcopy)
- $(kecho) ' Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'
+ @$(kecho) ' Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'
$(obj)/Image $(obj)/zImage: FORCE
@echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)'
@@ -46,14 +46,14 @@ $(obj)/xipImage: FORCE
$(obj)/Image: vmlinux FORCE
$(call if_changed,objcopy)
- $(kecho) ' Kernel: $@ is ready'
+ @$(kecho) ' Kernel: $@ is ready'
$(obj)/compressed/vmlinux: $(obj)/Image FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
- $(kecho) ' Kernel: $@ is ready'
+ @$(kecho) ' Kernel: $@ is ready'
endif
@@ -78,7 +78,7 @@ fi
$(obj)/uImage: $(obj)/zImage FORCE
@$(check_for_multiple_loadaddr)
$(call if_changed,uimage)
- $(kecho) ' Image $@ is ready'
+ @$(kecho) ' Image $@ is ready'
$(obj)/bootp/bootp: $(obj)/zImage initrd FORCE
$(Q)$(MAKE) $(build)=$(obj)/bootp $@
@@ -86,7 +86,7 @@ $(obj)/bootp/bootp: $(obj)/zImage initrd FORCE
$(obj)/bootpImage: $(obj)/bootp/bootp FORCE
$(call if_changed,objcopy)
- $(kecho) ' Kernel: $@ is ready'
+ @$(kecho) ' Kernel: $@ is ready'
PHONY += initrd FORCE
initrd:
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 90275f036cd1..49ca86e37b8d 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -652,6 +652,15 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size
mov pc, lr
ENDPROC(__setup_mmu)
+@ Enable unaligned access on v6, to allow better code generation
+@ for the decompressor C code:
+__armv6_mmu_cache_on:
+ mrc p15, 0, r0, c1, c0, 0 @ read SCTLR
+ bic r0, r0, #2 @ A (no unaligned access fault)
+ orr r0, r0, #1 << 22 @ U (v6 unaligned access model)
+ mcr p15, 0, r0, c1, c0, 0 @ write SCTLR
+ b __armv4_mmu_cache_on
+
__arm926ejs_mmu_cache_on:
#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
mov r0, #4 @ put dcache in WT mode
@@ -694,6 +703,9 @@ __armv7_mmu_cache_on:
bic r0, r0, #1 << 28 @ clear SCTLR.TRE
orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
orr r0, r0, #0x003c @ write buffer
+ bic r0, r0, #2 @ A (no unaligned access fault)
+ orr r0, r0, #1 << 22 @ U (v6 unaligned access model)
+ @ (needed for ARM1176)
#ifdef CONFIG_MMU
#ifdef CONFIG_CPU_ENDIAN_BE8
orr r0, r0, #1 << 25 @ big-endian page tables
@@ -914,7 +926,7 @@ proc_types:
.word 0x0007b000 @ ARMv6
.word 0x000ff000
- W(b) __armv4_mmu_cache_on
+ W(b) __armv6_mmu_cache_on
W(b) __armv4_mmu_cache_off
W(b) __armv6_mmu_cache_flush
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 22404959b397..262493752234 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -1,21 +1,37 @@
ifeq ($(CONFIG_OF),y)
-dtb-$(CONFIG_ARCH_AT91) += aks-cdu.dtb \
- at91sam9263ek.dtb \
- at91sam9g20ek_2mmc.dtb \
- at91sam9g20ek.dtb \
- at91sam9g25ek.dtb \
- at91sam9m10g45ek.dtb \
- at91sam9n12ek.dtb \
- ethernut5.dtb \
- evk-pro3.dtb \
- kizbox.dtb \
- tny_a9260.dtb \
- tny_a9263.dtb \
- tny_a9g20.dtb \
- usb_a9260.dtb \
- usb_a9263.dtb \
- usb_a9g20.dtb
+# Keep at91 dtb files sorted alphabetically for each SoC
+# rm9200
+dtb-$(CONFIG_ARCH_AT91) += at91rm9200ek.dtb
+# sam9260
+dtb-$(CONFIG_ARCH_AT91) += animeo_ip.dtb
+dtb-$(CONFIG_ARCH_AT91) += aks-cdu.dtb
+dtb-$(CONFIG_ARCH_AT91) += ethernut5.dtb
+dtb-$(CONFIG_ARCH_AT91) += evk-pro3.dtb
+dtb-$(CONFIG_ARCH_AT91) += tny_a9260.dtb
+dtb-$(CONFIG_ARCH_AT91) += usb_a9260.dtb
+# sam9263
+dtb-$(CONFIG_ARCH_AT91) += at91sam9263ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += tny_a9263.dtb
+dtb-$(CONFIG_ARCH_AT91) += usb_a9263.dtb
+# sam9g20
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g20ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g20ek_2mmc.dtb
+dtb-$(CONFIG_ARCH_AT91) += kizbox.dtb
+dtb-$(CONFIG_ARCH_AT91) += tny_a9g20.dtb
+dtb-$(CONFIG_ARCH_AT91) += usb_a9g20.dtb
+# sam9g45
+dtb-$(CONFIG_ARCH_AT91) += at91sam9m10g45ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += pm9g45.dtb
+# sam9n12
+dtb-$(CONFIG_ARCH_AT91) += at91sam9n12ek.dtb
+# sam9x5
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g15ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g25ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9g35ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9x25ek.dtb
+dtb-$(CONFIG_ARCH_AT91) += at91sam9x35ek.dtb
+
dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
dtb-$(CONFIG_ARCH_DOVE) += dove-cm-a510.dtb \
dove-cubox.dtb \
diff --git a/arch/arm/boot/dts/animeo_ip.dts b/arch/arm/boot/dts/animeo_ip.dts
new file mode 100644
index 000000000000..74d92cd29d87
--- /dev/null
+++ b/arch/arm/boot/dts/animeo_ip.dts
@@ -0,0 +1,178 @@
+/*
+ * animeo_ip.dts - Device Tree file for Somfy Animeo IP Boards
+ *
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only.
+ */
+
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+
+/ {
+ model = "Somfy Animeo IP";
+ compatible = "somfy,animeo-ip", "atmel,at91sam9260", "atmel,at91sam9";
+
+ aliases {
+ serial0 = &usart1;
+ serial1 = &usart2;
+ serial2 = &usart0;
+ serial3 = &dbgu;
+ serial4 = &usart3;
+ serial5 = &uart0;
+ serial6 = &uart1;
+ };
+
+ chosen {
+ linux,stdout-path = &usart2;
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <18432000>;
+ };
+ };
+
+ ahb {
+ apb {
+ usart0: serial@fffb0000 {
+ pinctrl-0 = <&pinctrl_usart0 &pinctrl_usart0_rts>;
+ linux,rs485-enabled-at-boot-time;
+ status = "okay";
+ };
+
+ usart1: serial@fffb4000 {
+ pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts>;
+ linux,rs485-enabled-at-boot-time;
+ status = "okay";
+ };
+
+ usart2: serial@fffb8000 {
+ pinctrl-0 = <&pinctrl_usart2>;
+ status = "okay";
+ };
+
+ macb0: ethernet@fffc4000 {
+ pinctrl-0 = <&pinctrl_macb_rmii &pinctrl_macb_rmii_mii>;
+ phy-mode = "mii";
+ status = "okay";
+ };
+
+ mmc0: mmc@fffa8000 {
+ pinctrl-0 = <&pinctrl_mmc0_clk
+ &pinctrl_mmc0_slot1_cmd_dat0
+ &pinctrl_mmc0_slot1_dat1_3>;
+ status = "okay";
+
+ slot@1 {
+ reg = <1>;
+ bus-width = <4>;
+ };
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x8000>;
+ };
+
+ barebox@8000 {
+ label = "barebox";
+ reg = <0x8000 0x40000>;
+ };
+
+ bareboxenv@48000 {
+ label = "bareboxenv";
+ reg = <0x48000 0x8000>;
+ };
+
+ user_block@0x50000 {
+ label = "user_block";
+ reg = <0x50000 0xb0000>;
+ };
+
+ kernel@100000 {
+ label = "kernel";
+ reg = <0x100000 0x1b0000>;
+ };
+
+ root@2b0000 {
+ label = "root";
+ reg = <0x2b0000 0x1D50000>;
+ };
+ };
+
+ usb0: ohci@00500000 {
+ num-ports = <2>;
+ atmel,vbus-gpio = <&pioB 15 1>;
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power_green {
+ label = "power_green";
+ gpios = <&pioC 17 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ power_red {
+ label = "power_red";
+ gpios = <&pioA 2 0>;
+ };
+
+ tx_green {
+ label = "tx_green";
+ gpios = <&pioC 19 0>;
+ };
+
+ tx_red {
+ label = "tx_red";
+ gpios = <&pioC 18 0>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ keyswitch_in {
+ label = "keyswitch_in";
+ gpios = <&pioB 1 0>;
+ linux,code = <28>;
+ gpio-key,wakeup;
+ };
+
+ error_in {
+ label = "error_in";
+ gpios = <&pioB 2 0>;
+ linux,code = <29>;
+ gpio-key,wakeup;
+ };
+
+ btn {
+ label = "btn";
+ gpios = <&pioC 23 0>;
+ linux,code = <31>;
+ gpio-key,wakeup;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
new file mode 100644
index 000000000000..e154f242c680
--- /dev/null
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -0,0 +1,349 @@
+/*
+ * at91rm9200.dtsi - Device Tree Include file for AT91RM9200 family SoC
+ *
+ * Copyright (C) 2011 Atmel,
+ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
+ * 2012 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Based on at91sam9260.dtsi
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Atmel AT91RM9200 family SoC";
+ compatible = "atmel,at91rm9200";
+ interrupt-parent = <&aic>;
+
+ aliases {
+ serial0 = &dbgu;
+ serial1 = &usart0;
+ serial2 = &usart1;
+ serial3 = &usart2;
+ serial4 = &usart3;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
+ };
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm920t";
+ };
+ };
+
+ memory {
+ reg = <0x20000000 0x04000000>;
+ };
+
+ ahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+ #interrupt-cells = <3>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+ atmel,external-irqs = <25 26 27 28 29 30 31>;
+ };
+
+ ramc0: ramc@ffffff00 {
+ compatible = "atmel,at91rm9200-sdramc";
+ reg = <0xffffff00 0x100>;
+ };
+
+ pmc: pmc@fffffc00 {
+ compatible = "atmel,at91rm9200-pmc";
+ reg = <0xfffffc00 0x100>;
+ };
+
+ st: timer@fffffd00 {
+ compatible = "atmel,at91rm9200-st";
+ reg = <0xfffffd00 0x100>;
+ interrupts = <1 4 7>;
+ };
+
+ tcb0: timer@fffa0000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa0000 0x100>;
+ interrupts = <17 4 0 18 4 0 19 4 0>;
+ };
+
+ tcb1: timer@fffa4000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa4000 0x100>;
+ interrupts = <20 4 0 21 4 0 22 4 0>;
+ };
+
+ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
+ atmel,mux-mask = <
+ /* A B */
+ 0xffffffff 0xffffffff /* pioA */
+ 0xffffffff 0x083fffff /* pioB */
+ 0xffff3fff 0x00000000 /* pioC */
+ 0x03ff87ff 0x0fffff80 /* pioD */
+ >;
+
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <0 30 0x1 0x0 /* PA30 periph A */
+ 0 31 0x1 0x1>; /* PA31 periph with pullup */
+ };
+ };
+
+ uart0 {
+ pinctrl_uart0: uart0-0 {
+ atmel,pins =
+ <0 17 0x1 0x0 /* PA17 periph A */
+ 0 18 0x1 0x0>; /* PA18 periph A */
+ };
+
+ pinctrl_uart0_rts: uart0_rts-0 {
+ atmel,pins =
+ <0 20 0x1 0x0>; /* PA20 periph A */
+ };
+
+ pinctrl_uart0_cts: uart0_cts-0 {
+ atmel,pins =
+ <0 21 0x1 0x0>; /* PA21 periph A */
+ };
+ };
+
+ uart1 {
+ pinctrl_uart1: uart1-0 {
+ atmel,pins =
+ <1 20 0x1 0x1 /* PB20 periph A with pullup */
+ 1 21 0x1 0x0>; /* PB21 periph A */
+ };
+
+ pinctrl_uart1_rts: uart1_rts-0 {
+ atmel,pins =
+ <1 24 0x1 0x0>; /* PB24 periph A */
+ };
+
+ pinctrl_uart1_cts: uart1_cts-0 {
+ atmel,pins =
+ <1 26 0x1 0x0>; /* PB26 periph A */
+ };
+
+ pinctrl_uart1_dtr_dsr: uart1_dtr_dsr-0 {
+ atmel,pins =
+ <1 19 0x1 0x0 /* PB19 periph A */
+ 1 25 0x1 0x0>; /* PB25 periph A */
+ };
+
+ pinctrl_uart1_dcd: uart1_dcd-0 {
+ atmel,pins =
+ <1 23 0x1 0x0>; /* PB23 periph A */
+ };
+
+ pinctrl_uart1_ri: uart1_ri-0 {
+ atmel,pins =
+ <1 18 0x1 0x0>; /* PB18 periph A */
+ };
+ };
+
+ uart2 {
+ pinctrl_uart2: uart2-0 {
+ atmel,pins =
+ <0 22 0x1 0x0 /* PA22 periph A */
+ 0 23 0x1 0x1>; /* PA23 periph A with pullup */
+ };
+
+ pinctrl_uart2_rts: uart2_rts-0 {
+ atmel,pins =
+ <0 30 0x2 0x0>; /* PA30 periph B */
+ };
+
+ pinctrl_uart2_cts: uart2_cts-0 {
+ atmel,pins =
+ <0 31 0x2 0x0>; /* PA31 periph B */
+ };
+ };
+
+ uart3 {
+ pinctrl_uart3: uart3-0 {
+ atmel,pins =
+ <0 5 0x2 0x1 /* PA5 periph B with pullup */
+ 0 6 0x2 0x0>; /* PA6 periph B */
+ };
+
+ pinctrl_uart3_rts: uart3_rts-0 {
+ atmel,pins =
+ <1 0 0x2 0x0>; /* PB0 periph B */
+ };
+
+ pinctrl_uart3_cts: uart3_cts-0 {
+ atmel,pins =
+ <1 1 0x2 0x0>; /* PB1 periph B */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <2 2 0x0 0x1 /* PC2 gpio RDY pin pull_up */
+ 1 1 0x0 0x1>; /* PB1 gpio CD pin pull_up */
+ };
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x200>;
+ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
+ status = "disabled";
+ };
+
+ usart0: serial@fffc0000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffc0000 0x200>;
+ interrupts = <6 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ status = "disabled";
+ };
+
+ usart1: serial@fffc4000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffc4000 0x200>;
+ interrupts = <7 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "disabled";
+ };
+
+ usart2: serial@fffc8000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffc8000 0x200>;
+ interrupts = <8 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "disabled";
+ };
+
+ usart3: serial@fffcc000 {
+ compatible = "atmel,at91rm9200-usart";
+ reg = <0xfffcc000 0x200>;
+ interrupts = <23 4 5>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fffb0000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfffb0000 0x4000>;
+ interrupts = <11 4 2>;
+ status = "disabled";
+ };
+ };
+
+ nand0: nand@40000000 {
+ compatible = "atmel,at91rm9200-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x40000000 0x10000000>;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
+ nand-ecc-mode = "soft";
+ gpios = <&pioC 2 0
+ 0
+ &pioB 1 0
+ >;
+ status = "disabled";
+ };
+
+ usb0: ohci@00300000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00300000 0x100000>;
+ interrupts = <23 4 2>;
+ status = "disabled";
+ };
+ };
+
+ i2c@0 {
+ compatible = "i2c-gpio";
+ gpios = <&pioA 23 0 /* sda */
+ &pioA 24 0 /* scl */
+ >;
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts
new file mode 100644
index 000000000000..8aa48931e0a2
--- /dev/null
+++ b/arch/arm/boot/dts/at91rm9200ek.dts
@@ -0,0 +1,79 @@
+/*
+ * at91rm9200ek.dts - Device Tree file for Atmel AT91RM9200 evaluation kit
+ *
+ * Copyright (C) 2012 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91rm9200.dtsi"
+
+/ {
+ model = "Atmel AT91RM9200 evaluation kit";
+ compatible = "atmel,at91rm9200ek", "atmel,at91rm9200";
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <18432000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ usart1: serial@fffc4000 {
+ pinctrl-0 =
+ <&pinctrl_uart1
+ &pinctrl_uart1_rts
+ &pinctrl_uart1_cts
+ &pinctrl_uart1_dtr_dsr
+ &pinctrl_uart1_dcd
+ &pinctrl_uart1_ri>;
+ status = "okay";
+ };
+
+ usb1: gadget@fffb0000 {
+ atmel,vbus-gpio = <&pioD 4 0>;
+ status = "okay";
+ };
+ };
+
+ usb0: ohci@00300000 {
+ num-ports = <2>;
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ ds2 {
+ label = "green";
+ gpios = <&pioB 0 0x1>;
+ linux,default-trigger = "mmc0";
+ };
+
+ ds4 {
+ label = "yellow";
+ gpios = <&pioB 1 0x1>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ ds6 {
+ label = "red";
+ gpios = <&pioB 2 0x1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index d410581a5a85..b1d3fab60e0a 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -21,8 +21,8 @@
serial2 = &usart1;
serial3 = &usart2;
serial4 = &usart3;
- serial5 = &usart4;
- serial6 = &usart5;
+ serial5 = &uart0;
+ serial6 = &uart1;
gpio0 = &pioA;
gpio1 = &pioB;
gpio2 = &pioC;
@@ -98,40 +98,250 @@
interrupts = <26 4 0 27 4 0 28 4 0>;
};
- pioA: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x600>;
+
+ atmel,mux-mask = <
+ /* A B */
+ 0xffffffff 0xffc00c3b /* pioA */
+ 0xffffffff 0x7fff3ccf /* pioB */
+ 0xffffffff 0x007fffff /* pioC */
+ >;
+
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <1 14 0x1 0x0 /* PB14 periph A */
+ 1 15 0x1 0x1>; /* PB15 periph with pullup */
+ };
+ };
- pioB: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <1 4 0x1 0x0 /* PB4 periph A */
+ 1 5 0x1 0x0>; /* PB5 periph A */
+ };
+
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins =
+ <1 26 0x1 0x0>; /* PB26 periph A */
+ };
+
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins =
+ <1 27 0x1 0x0>; /* PB27 periph A */
+ };
+
+ pinctrl_usart0_dtr_dsr: usart0_dtr_dsr-0 {
+ atmel,pins =
+ <1 24 0x1 0x0 /* PB24 periph A */
+ 1 22 0x1 0x0>; /* PB22 periph A */
+ };
+
+ pinctrl_usart0_dcd: usart0_dcd-0 {
+ atmel,pins =
+ <1 23 0x1 0x0>; /* PB23 periph A */
+ };
+
+ pinctrl_usart0_ri: usart0_ri-0 {
+ atmel,pins =
+ <1 25 0x1 0x0>; /* PB25 periph A */
+ };
+ };
- pioC: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
- interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <2 6 0x1 0x1 /* PB6 periph A with pullup */
+ 2 7 0x1 0x0>; /* PB7 periph A */
+ };
+
+ pinctrl_usart1_rts: usart1_rts-0 {
+ atmel,pins =
+ <1 28 0x1 0x0>; /* PB28 periph A */
+ };
+
+ pinctrl_usart1_cts: usart1_cts-0 {
+ atmel,pins =
+ <1 29 0x1 0x0>; /* PB29 periph A */
+ };
+ };
+
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ atmel,pins =
+ <1 8 0x1 0x1 /* PB8 periph A with pullup */
+ 1 9 0x1 0x0>; /* PB9 periph A */
+ };
+
+ pinctrl_usart2_rts: usart2_rts-0 {
+ atmel,pins =
+ <0 4 0x1 0x0>; /* PA4 periph A */
+ };
+
+ pinctrl_usart2_cts: usart2_cts-0 {
+ atmel,pins =
+ <0 5 0x1 0x0>; /* PA5 periph A */
+ };
+ };
+
+ usart3 {
+ pinctrl_usart3: usart3-0 {
+ atmel,pins =
+ <2 10 0x1 0x1 /* PB10 periph A with pullup */
+ 2 11 0x1 0x0>; /* PB11 periph A */
+ };
+
+ pinctrl_usart3_rts: usart3_rts-0 {
+ atmel,pins =
+ <3 8 0x2 0x0>; /* PB8 periph B */
+ };
+
+ pinctrl_usart3_cts: usart3_cts-0 {
+ atmel,pins =
+ <3 10 0x2 0x0>; /* PB10 periph B */
+ };
+ };
+
+ uart0 {
+ pinctrl_uart0: uart0-0 {
+ atmel,pins =
+ <0 31 0x2 0x1 /* PA31 periph B with pullup */
+ 0 30 0x2 0x0>; /* PA30 periph B */
+ };
+ };
+
+ uart1 {
+ pinctrl_uart1: uart1-0 {
+ atmel,pins =
+ <2 12 0x1 0x1 /* PB12 periph A with pullup */
+ 2 13 0x1 0x0>; /* PB13 periph A */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <2 13 0x0 0x1 /* PC13 gpio RDY pin pull_up */
+ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
+ };
+ };
+
+ macb {
+ pinctrl_macb_rmii: macb_rmii-0 {
+ atmel,pins =
+ <0 12 0x1 0x0 /* PA12 periph A */
+ 0 13 0x1 0x0 /* PA13 periph A */
+ 0 14 0x1 0x0 /* PA14 periph A */
+ 0 15 0x1 0x0 /* PA15 periph A */
+ 0 16 0x1 0x0 /* PA16 periph A */
+ 0 17 0x1 0x0 /* PA17 periph A */
+ 0 18 0x1 0x0 /* PA18 periph A */
+ 0 19 0x1 0x0 /* PA19 periph A */
+ 0 20 0x1 0x0 /* PA20 periph A */
+ 0 21 0x1 0x0>; /* PA21 periph A */
+ };
+
+ pinctrl_macb_rmii_mii: macb_rmii_mii-0 {
+ atmel,pins =
+ <0 22 0x2 0x0 /* PA22 periph B */
+ 0 23 0x2 0x0 /* PA23 periph B */
+ 0 24 0x2 0x0 /* PA24 periph B */
+ 0 25 0x2 0x0 /* PA25 periph B */
+ 0 26 0x2 0x0 /* PA26 periph B */
+ 0 27 0x2 0x0 /* PA27 periph B */
+ 0 28 0x2 0x0 /* PA28 periph B */
+ 0 29 0x2 0x0>; /* PA29 periph B */
+ };
+
+ pinctrl_macb_rmii_mii_alt: macb_rmii_mii-1 {
+ atmel,pins =
+ <0 10 0x2 0x0 /* PA10 periph B */
+ 0 11 0x2 0x0 /* PA11 periph B */
+ 0 24 0x2 0x0 /* PA24 periph B */
+ 0 25 0x2 0x0 /* PA25 periph B */
+ 0 26 0x2 0x0 /* PA26 periph B */
+ 0 27 0x2 0x0 /* PA27 periph B */
+ 0 28 0x2 0x0 /* PA28 periph B */
+ 0 29 0x2 0x0>; /* PA29 periph B */
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0_clk: mmc0_clk-0 {
+ atmel,pins =
+ <0 8 0x1 0x0>; /* PA8 periph A */
+ };
+
+ pinctrl_mmc0_slot0_cmd_dat0: mmc0_slot0_cmd_dat0-0 {
+ atmel,pins =
+ <0 7 0x1 0x1 /* PA7 periph A with pullup */
+ 0 6 0x1 0x1>; /* PA6 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 9 0x1 0x1 /* PA9 periph A with pullup */
+ 0 10 0x1 0x1 /* PA10 periph A with pullup */
+ 0 11 0x1 0x1>; /* PA11 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot1_cmd_dat0: mmc0_slot1_cmd_dat0-0 {
+ atmel,pins =
+ <0 1 0x2 0x1 /* PA1 periph B with pullup */
+ 0 0 0x2 0x1>; /* PA0 periph B with pullup */
+ };
+
+ pinctrl_mmc0_slot1_dat1_3: mmc0_slot1_dat1_3-0 {
+ atmel,pins =
+ <0 5 0x2 0x1 /* PA5 periph B with pullup */
+ 0 4 0x2 0x1 /* PA4 periph B with pullup */
+ 0 3 0x2 0x1>; /* PA3 periph B with pullup */
+ };
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
dbgu: serial@fffff200 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffff200 0x200>;
interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
status = "disabled";
};
@@ -141,6 +351,8 @@
interrupts = <6 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
};
@@ -150,6 +362,8 @@
interrupts = <7 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
};
@@ -159,6 +373,8 @@
interrupts = <8 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
};
@@ -168,24 +384,30 @@
interrupts = <23 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart3>;
status = "disabled";
};
- usart4: serial@fffd4000 {
+ uart0: serial@fffd4000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffd4000 0x200>;
interrupts = <24 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
status = "disabled";
};
- usart5: serial@fffd8000 {
+ uart1: serial@fffd8000 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffd8000 0x200>;
interrupts = <25 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
status = "disabled";
};
@@ -193,6 +415,8 @@
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xfffc4000 0x100>;
interrupts = <21 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb_rmii>;
status = "disabled";
};
@@ -212,6 +436,15 @@
status = "disabled";
};
+ mmc0: mmc@fffa8000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffa8000 0x600>;
+ interrupts = <9 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
adc0: adc@fffe0000 {
compatible = "atmel,at91sam9260-adc";
reg = <0xfffe0000 0x100>;
@@ -257,6 +490,8 @@
>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
gpios = <&pioC 13 0
&pioC 14 0
0
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 3e6e5c1abbf3..66106eecf1ed 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -89,60 +89,243 @@
reg = <0xfffffd10 0x10>;
};
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff200 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ pinctrl@fffff200 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff200 0xfffff200 0xa00>;
- pioB: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ atmel,mux-mask = <
+ /* A B */
+ 0xfffffffb 0xffffe07f /* pioA */
+ 0x0007ffff 0x39072fff /* pioB */
+ 0xffffffff 0x3ffffff8 /* pioC */
+ 0xfffffbff 0xffffffff /* pioD */
+ 0xffe00fff 0xfbfcff00 /* pioE */
+ >;
- pioC: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
- interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <2 30 0x1 0x0 /* PC30 periph A */
+ 2 31 0x1 0x1>; /* PC31 periph with pullup */
+ };
+ };
- pioD: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
- interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <0 26 0x1 0x1 /* PA26 periph A with pullup */
+ 0 27 0x1 0x0>; /* PA27 periph A */
+ };
- pioE: gpio@fffffa00 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
- interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins =
+ <0 28 0x1 0x0>; /* PA28 periph A */
+ };
+
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins =
+ <0 29 0x1 0x0>; /* PA29 periph A */
+ };
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <3 0 0x1 0x1 /* PD0 periph A with pullup */
+ 3 1 0x1 0x0>; /* PD1 periph A */
+ };
+
+ pinctrl_usart1_rts: usart1_rts-0 {
+ atmel,pins =
+ <3 7 0x2 0x0>; /* PD7 periph B */
+ };
+
+ pinctrl_usart1_cts: usart1_cts-0 {
+ atmel,pins =
+ <3 8 0x2 0x0>; /* PD8 periph B */
+ };
+ };
+
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ atmel,pins =
+ <3 2 0x1 0x1 /* PD2 periph A with pullup */
+ 3 3 0x1 0x0>; /* PD3 periph A */
+ };
+
+ pinctrl_usart2_rts: usart2_rts-0 {
+ atmel,pins =
+ <3 5 0x2 0x0>; /* PD5 periph B */
+ };
+
+ pinctrl_usart2_cts: usart2_cts-0 {
+ atmel,pins =
+ <4 6 0x2 0x0>; /* PD6 periph B */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <0 22 0x0 0x1 /* PA22 gpio RDY pin pull_up*/
+ 3 15 0x0 0x1>; /* PD15 gpio enable pin pull_up */
+ };
+ };
+
+ macb {
+ pinctrl_macb_rmii: macb_rmii-0 {
+ atmel,pins =
+ <2 25 0x2 0x0 /* PC25 periph B */
+ 4 21 0x1 0x0 /* PE21 periph A */
+ 4 23 0x1 0x0 /* PE23 periph A */
+ 4 24 0x1 0x0 /* PE24 periph A */
+ 4 25 0x1 0x0 /* PE25 periph A */
+ 4 26 0x1 0x0 /* PE26 periph A */
+ 4 27 0x1 0x0 /* PE27 periph A */
+ 4 28 0x1 0x0 /* PE28 periph A */
+ 4 29 0x1 0x0 /* PE29 periph A */
+ 4 30 0x1 0x0>; /* PE30 periph A */
+ };
+
+ pinctrl_macb_rmii_mii: macb_rmii_mii-0 {
+ atmel,pins =
+ <2 20 0x2 0x0 /* PC20 periph B */
+ 2 21 0x2 0x0 /* PC21 periph B */
+ 2 22 0x2 0x0 /* PC22 periph B */
+ 2 23 0x2 0x0 /* PC23 periph B */
+ 2 24 0x2 0x0 /* PC24 periph B */
+ 2 25 0x2 0x0 /* PC25 periph B */
+ 2 27 0x2 0x0 /* PC27 periph B */
+ 4 22 0x2 0x0>; /* PE22 periph B */
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0_clk: mmc0_clk-0 {
+ atmel,pins =
+ <0 12 0x1 0x0>; /* PA12 periph A */
+ };
+
+ pinctrl_mmc0_slot0_cmd_dat0: mmc0_slot0_cmd_dat0-0 {
+ atmel,pins =
+ <0 1 0x1 0x1 /* PA1 periph A with pullup */
+ 0 0 0x1 0x1>; /* PA0 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 3 0x1 0x1 /* PA3 periph A with pullup */
+ 0 4 0x1 0x1 /* PA4 periph A with pullup */
+ 0 5 0x1 0x1>; /* PA5 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot1_cmd_dat0: mmc0_slot1_cmd_dat0-0 {
+ atmel,pins =
+ <0 16 0x1 0x1 /* PA16 periph A with pullup */
+ 0 17 0x1 0x1>; /* PA17 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot1_dat1_3: mmc0_slot1_dat1_3-0 {
+ atmel,pins =
+ <0 18 0x1 0x1 /* PA18 periph A with pullup */
+ 0 19 0x1 0x1 /* PA19 periph A with pullup */
+ 0 20 0x1 0x1>; /* PA20 periph A with pullup */
+ };
+ };
+
+ mmc1 {
+ pinctrl_mmc1_clk: mmc1_clk-0 {
+ atmel,pins =
+ <0 6 0x1 0x0>; /* PA6 periph A */
+ };
+
+ pinctrl_mmc1_slot0_cmd_dat0: mmc1_slot0_cmd_dat0-0 {
+ atmel,pins =
+ <0 7 0x1 0x1 /* PA7 periph A with pullup */
+ 0 8 0x1 0x1>; /* PA8 periph A with pullup */
+ };
+
+ pinctrl_mmc1_slot0_dat1_3: mmc1_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 9 0x1 0x1 /* PA9 periph A with pullup */
+ 0 10 0x1 0x1 /* PA10 periph A with pullup */
+ 0 11 0x1 0x1>; /* PA11 periph A with pullup */
+ };
+
+ pinctrl_mmc1_slot1_cmd_dat0: mmc1_slot1_cmd_dat0-0 {
+ atmel,pins =
+ <0 21 0x1 0x1 /* PA21 periph A with pullup */
+ 0 22 0x1 0x1>; /* PA22 periph A with pullup */
+ };
+
+ pinctrl_mmc1_slot1_dat1_3: mmc1_slot1_dat1_3-0 {
+ atmel,pins =
+ <0 23 0x1 0x1 /* PA23 periph A with pullup */
+ 0 24 0x1 0x1 /* PA24 periph A with pullup */
+ 0 25 0x1 0x1>; /* PA25 periph A with pullup */
+ };
+ };
+
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
dbgu: serial@ffffee00 {
compatible = "atmel,at91sam9260-usart";
reg = <0xffffee00 0x200>;
interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
status = "disabled";
};
@@ -152,6 +335,8 @@
interrupts = <7 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
};
@@ -161,6 +346,8 @@
interrupts = <8 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
};
@@ -170,6 +357,8 @@
interrupts = <9 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
};
@@ -177,6 +366,8 @@
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xfffbc000 0x100>;
interrupts = <21 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb_rmii>;
status = "disabled";
};
@@ -195,6 +386,24 @@
#size-cells = <0>;
status = "disabled";
};
+
+ mmc0: mmc@fff80000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff80000 0x600>;
+ interrupts = <10 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ mmc1: mmc@fff84000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff84000 0x600>;
+ interrupts = <11 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
@@ -206,6 +415,8 @@
>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
gpios = <&pioA 22 0
&pioD 15 0
0
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
index f86ac4b609fc..1eb08728f527 100644
--- a/arch/arm/boot/dts/at91sam9263ek.dts
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -38,6 +38,10 @@
};
usart0: serial@fff8c000 {
+ pinctrl-0 = <
+ &pinctrl_usart0
+ &pinctrl_usart0_rts
+ &pinctrl_usart0_cts>;
status = "okay";
};
@@ -50,6 +54,31 @@
atmel,vbus-gpio = <&pioA 25 0>;
status = "okay";
};
+
+ mmc0: mmc@fff80000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc0
+ &pinctrl_mmc0_clk
+ &pinctrl_mmc0_slot0_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioE 18 0>;
+ wp-gpios = <&pioE 19 0>;
+ };
+ };
+
+ pinctrl@fffff200 {
+ mmc0 {
+ pinctrl_board_mmc0: mmc0-board {
+ atmel,pins =
+ <5 18 0x0 0x5 /* PE18 gpio CD pin pull up and deglitch */
+ 5 19 0x0 0x1>; /* PE19 gpio WP pin pull up */
+ };
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi
new file mode 100644
index 000000000000..fbe7a7089c2a
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g15.dtsi
@@ -0,0 +1,28 @@
+/*
+ * at91sam9g15.dtsi - Device Tree Include file for AT91SAM9G15 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G15 SoC";
+ compatible = "atmel, at91sam9g15, atmel,at91sam9x5";
+
+ ahb {
+ apb {
+ pinctrl@fffff400 {
+ atmel,mux-mask = <
+ /* A B C */
+ 0xffffffff 0xffe0399f 0x00000000 /* pioA */
+ 0x00040000 0x00047e3f 0x00000000 /* pioB */
+ 0xfdffffff 0x00000000 0xb83fffff /* pioC */
+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
+ >;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts
new file mode 100644
index 000000000000..86dd3f6d938f
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g15ek.dts
@@ -0,0 +1,16 @@
+/*
+ * at91sam9g15ek.dts - Device Tree file for AT91SAM9G15-EK board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9g15.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G25-EK";
+ compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
index f1b2e148ac8c..66467b113126 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
+++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
@@ -12,6 +12,32 @@
model = "Atmel at91sam9g20ek 2 mmc";
compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
+ ahb {
+ apb{
+ mmc0: mmc@fffa8000 {
+ /* clk already mux wuth slot0 */
+ pinctrl-0 = <
+ &pinctrl_board_mmc0_slot0
+ &pinctrl_mmc0_slot0_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioC 2 0>;
+ };
+ };
+
+ pinctrl@fffff400 {
+ mmc0_slot0 {
+ pinctrl_board_mmc0_slot0: mmc0_slot0-board {
+ atmel,pins =
+ <2 2 0x0 0x5>; /* PC2 gpio CD pin pull up and deglitch */
+ };
+ };
+ };
+ };
+ };
+
leds {
compatible = "gpio-leds";
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index e6391a4e6649..32a500a0e481 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -35,6 +35,13 @@
};
usart0: serial@fffb0000 {
+ pinctrl-0 =
+ <&pinctrl_usart0
+ &pinctrl_usart0_rts
+ &pinctrl_usart0_cts
+ &pinctrl_usart0_dtr_dsr
+ &pinctrl_usart0_dcd
+ &pinctrl_usart0_ri>;
status = "okay";
};
@@ -51,6 +58,29 @@
atmel,vbus-gpio = <&pioC 5 0>;
status = "okay";
};
+
+ mmc0: mmc@fffa8000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc0_slot1
+ &pinctrl_mmc0_clk
+ &pinctrl_mmc0_slot1_cmd_dat0
+ &pinctrl_mmc0_slot1_dat1_3>;
+ status = "okay";
+ slot@1 {
+ reg = <1>;
+ bus-width = <4>;
+ cd-gpios = <&pioC 9 0>;
+ };
+ };
+
+ pinctrl@fffff400 {
+ mmc0_slot1 {
+ pinctrl_board_mmc0_slot1: mmc0_slot1-board {
+ atmel,pins =
+ <2 9 0x0 0x5>; /* PC9 gpio CD pin pull up and deglitch */
+ };
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi
new file mode 100644
index 000000000000..05a718fb83c4
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g25.dtsi
@@ -0,0 +1,28 @@
+/*
+ * at91sam9g25.dtsi - Device Tree Include file for AT91SAM9G25 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G25 SoC";
+ compatible = "atmel, at91sam9g25, atmel,at91sam9x5";
+
+ ahb {
+ apb {
+ pinctrl@fffff400 {
+ atmel,mux-mask = <
+ /* A B C */
+ 0xffffffff 0xffe0399f 0xc000001c /* pioA */
+ 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */
+ 0x80000000 0x07c0ffff 0xb83fffff /* pioC */
+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
+ >;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts
index 877c08f06763..c5ab16fba059 100644
--- a/arch/arm/boot/dts/at91sam9g25ek.dts
+++ b/arch/arm/boot/dts/at91sam9g25ek.dts
@@ -7,55 +7,10 @@
* Licensed under GPLv2 or later.
*/
/dts-v1/;
-/include/ "at91sam9x5.dtsi"
-/include/ "at91sam9x5cm.dtsi"
+/include/ "at91sam9g25.dtsi"
+/include/ "at91sam9x5ek.dtsi"
/ {
model = "Atmel AT91SAM9G25-EK";
compatible = "atmel,at91sam9g25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
-
- chosen {
- bootargs = "console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
- };
-
- ahb {
- apb {
- dbgu: serial@fffff200 {
- status = "okay";
- };
-
- usart0: serial@f801c000 {
- status = "okay";
- };
-
- macb0: ethernet@f802c000 {
- phy-mode = "rmii";
- status = "okay";
- };
-
- i2c0: i2c@f8010000 {
- status = "okay";
- };
-
- i2c1: i2c@f8014000 {
- status = "okay";
- };
-
- i2c2: i2c@f8018000 {
- status = "okay";
- };
- };
-
- usb0: ohci@00600000 {
- status = "okay";
- num-ports = <2>;
- atmel,vbus-gpio = <&pioD 19 1
- &pioD 20 1
- >;
- };
-
- usb1: ehci@00700000 {
- status = "okay";
- };
- };
};
diff --git a/arch/arm/boot/dts/at91sam9g35.dtsi b/arch/arm/boot/dts/at91sam9g35.dtsi
new file mode 100644
index 000000000000..f9d14a722794
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g35.dtsi
@@ -0,0 +1,28 @@
+/*
+ * at91sam9g35.dtsi - Device Tree Include file for AT91SAM9G35 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G35 SoC";
+ compatible = "atmel, at91sam9g35, atmel,at91sam9x5";
+
+ ahb {
+ apb {
+ pinctrl@fffff400 {
+ atmel,mux-mask = <
+ /* A B C */
+ 0xffffffff 0xffe0399f 0xc000000c /* pioA */
+ 0x000406ff 0x00047e3f 0x00000000 /* pioB */
+ 0xfdffffff 0x00000000 0xb83fffff /* pioC */
+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
+ >;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts
new file mode 100644
index 000000000000..95944bdd798d
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g35ek.dts
@@ -0,0 +1,16 @@
+/*
+ * at91sam9g35ek.dts - Device Tree file for AT91SAM9G35-EK board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9g35.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G35-EK";
+ compatible = "atmel,at91sam9g35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 3add030d61f8..0741caeeced1 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -108,60 +108,243 @@
interrupts = <21 4 0>;
};
- pioA: gpio@fffff200 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff200 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ pinctrl@fffff200 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff200 0xfffff200 0xa00>;
+
+ atmel,mux-mask = <
+ /* A B */
+ 0xffffffff 0xffc003ff /* pioA */
+ 0xffffffff 0x800f8f00 /* pioB */
+ 0xffffffff 0x00000e00 /* pioC */
+ 0xffffffff 0xff0c1381 /* pioD */
+ 0xffffffff 0x81ffff81 /* pioE */
+ >;
+
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <1 12 0x1 0x0 /* PB12 periph A */
+ 1 13 0x1 0x0>; /* PB13 periph A */
+ };
+ };
- pioB: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <1 19 0x1 0x1 /* PB19 periph A with pullup */
+ 1 18 0x1 0x0>; /* PB18 periph A */
+ };
+
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins =
+ <1 17 0x2 0x0>; /* PB17 periph B */
+ };
+
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins =
+ <1 15 0x2 0x0>; /* PB15 periph B */
+ };
+ };
- pioC: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
- interrupts = <4 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ uart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <1 4 0x1 0x1 /* PB4 periph A with pullup */
+ 1 5 0x1 0x0>; /* PB5 periph A */
+ };
+
+ pinctrl_usart1_rts: usart1_rts-0 {
+ atmel,pins =
+ <3 16 0x1 0x0>; /* PD16 periph A */
+ };
+
+ pinctrl_usart1_cts: usart1_cts-0 {
+ atmel,pins =
+ <3 17 0x1 0x0>; /* PD17 periph A */
+ };
+ };
- pioD: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
- interrupts = <5 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ atmel,pins =
+ <1 6 0x1 0x1 /* PB6 periph A with pullup */
+ 1 7 0x1 0x0>; /* PB7 periph A */
+ };
+
+ pinctrl_usart2_rts: usart2_rts-0 {
+ atmel,pins =
+ <2 9 0x2 0x0>; /* PC9 periph B */
+ };
+
+ pinctrl_usart2_cts: usart2_cts-0 {
+ atmel,pins =
+ <2 11 0x2 0x0>; /* PC11 periph B */
+ };
+ };
- pioE: gpio@fffffa00 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
- interrupts = <5 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ usart3 {
+ pinctrl_usart3: usart3-0 {
+ atmel,pins =
+ <1 8 0x1 0x1 /* PB9 periph A with pullup */
+ 1 9 0x1 0x0>; /* PB8 periph A */
+ };
+
+ pinctrl_usart3_rts: usart3_rts-0 {
+ atmel,pins =
+ <0 23 0x2 0x0>; /* PA23 periph B */
+ };
+
+ pinctrl_usart3_cts: usart3_cts-0 {
+ atmel,pins =
+ <0 24 0x2 0x0>; /* PA24 periph B */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <2 8 0x0 0x1 /* PC8 gpio RDY pin pull_up*/
+ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
+ };
+ };
+
+ macb {
+ pinctrl_macb_rmii: macb_rmii-0 {
+ atmel,pins =
+ <0 10 0x1 0x0 /* PA10 periph A */
+ 0 11 0x1 0x0 /* PA11 periph A */
+ 0 12 0x1 0x0 /* PA12 periph A */
+ 0 13 0x1 0x0 /* PA13 periph A */
+ 0 14 0x1 0x0 /* PA14 periph A */
+ 0 15 0x1 0x0 /* PA15 periph A */
+ 0 16 0x1 0x0 /* PA16 periph A */
+ 0 17 0x1 0x0 /* PA17 periph A */
+ 0 18 0x1 0x0 /* PA18 periph A */
+ 0 19 0x1 0x0>; /* PA19 periph A */
+ };
+
+ pinctrl_macb_rmii_mii: macb_rmii_mii-0 {
+ atmel,pins =
+ <0 6 0x2 0x0 /* PA6 periph B */
+ 0 7 0x2 0x0 /* PA7 periph B */
+ 0 8 0x2 0x0 /* PA8 periph B */
+ 0 9 0x2 0x0 /* PA9 periph B */
+ 0 27 0x2 0x0 /* PA27 periph B */
+ 0 28 0x2 0x0 /* PA28 periph B */
+ 0 29 0x2 0x0 /* PA29 periph B */
+ 0 30 0x2 0x0>; /* PA30 periph B */
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0_slot0_clk_cmd_dat0: mmc0_slot0_clk_cmd_dat0-0 {
+ atmel,pins =
+ <0 0 0x1 0x0 /* PA0 periph A */
+ 0 1 0x1 0x1 /* PA1 periph A with pullup */
+ 0 2 0x1 0x1>; /* PA2 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 3 0x1 0x1 /* PA3 periph A with pullup */
+ 0 4 0x1 0x1 /* PA4 periph A with pullup */
+ 0 5 0x1 0x1>; /* PA5 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat4_7: mmc0_slot0_dat4_7-0 {
+ atmel,pins =
+ <0 6 0x1 0x1 /* PA6 periph A with pullup */
+ 0 7 0x1 0x1 /* PA7 periph A with pullup */
+ 0 8 0x1 0x1 /* PA8 periph A with pullup */
+ 0 9 0x1 0x1>; /* PA9 periph A with pullup */
+ };
+ };
+
+ mmc1 {
+ pinctrl_mmc1_slot0_clk_cmd_dat0: mmc1_slot0_clk_cmd_dat0-0 {
+ atmel,pins =
+ <0 31 0x1 0x0 /* PA31 periph A */
+ 0 22 0x1 0x1 /* PA22 periph A with pullup */
+ 0 23 0x1 0x1>; /* PA23 periph A with pullup */
+ };
+
+ pinctrl_mmc1_slot0_dat1_3: mmc1_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 24 0x1 0x1 /* PA24 periph A with pullup */
+ 0 25 0x1 0x1 /* PA25 periph A with pullup */
+ 0 26 0x1 0x1>; /* PA26 periph A with pullup */
+ };
+
+ pinctrl_mmc1_slot0_dat4_7: mmc1_slot0_dat4_7-0 {
+ atmel,pins =
+ <0 27 0x1 0x1 /* PA27 periph A with pullup */
+ 0 28 0x1 0x1 /* PA28 periph A with pullup */
+ 0 29 0x1 0x1 /* PA29 periph A with pullup */
+ 0 20 0x1 0x1>; /* PA30 periph A with pullup */
+ };
+ };
+
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <4 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x200>;
+ interrupts = <5 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
dbgu: serial@ffffee00 {
compatible = "atmel,at91sam9260-usart";
reg = <0xffffee00 0x200>;
interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
status = "disabled";
};
@@ -171,6 +354,8 @@
interrupts = <7 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
};
@@ -180,6 +365,8 @@
interrupts = <8 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
};
@@ -189,6 +376,8 @@
interrupts = <9 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
};
@@ -198,6 +387,8 @@
interrupts = <10 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart3>;
status = "disabled";
};
@@ -205,6 +396,8 @@
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xfffbc000 0x100>;
interrupts = <25 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb_rmii>;
status = "disabled";
};
@@ -262,6 +455,24 @@
trigger-value = <0x6>;
};
};
+
+ mmc0: mmc@fff80000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfff80000 0x600>;
+ interrupts = <11 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ mmc1: mmc@fffd0000 {
+ compatible = "atmel,hsmci";
+ reg = <0xfffd0000 0x600>;
+ interrupts = <29 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
nand0: nand@40000000 {
@@ -273,6 +484,8 @@
>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
gpios = <&pioC 8 0
&pioC 14 0
0
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index 15e1dd43f625..20c31913c270 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -39,6 +39,10 @@
};
usart1: serial@fff90000 {
+ pinctrl-0 =
+ <&pinctrl_usart1
+ &pinctrl_usart1_rts
+ &pinctrl_usart1_cts>;
status = "okay";
};
@@ -54,6 +58,50 @@
i2c1: i2c@fff88000 {
status = "okay";
};
+
+ mmc0: mmc@fff80000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc0
+ &pinctrl_mmc0_slot0_clk_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 10 0>;
+ };
+ };
+
+ mmc1: mmc@fffd0000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc1
+ &pinctrl_mmc1_slot0_clk_cmd_dat0
+ &pinctrl_mmc1_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 11 0>;
+ wp-gpios = <&pioD 29 0>;
+ };
+ };
+
+ pinctrl@fffff200 {
+ mmc0 {
+ pinctrl_board_mmc0: mmc0-board {
+ atmel,pins =
+ <3 10 0x0 0x5>; /* PD10 gpio CD pin pull up and deglitch */
+ };
+ };
+
+ mmc1 {
+ pinctrl_board_mmc1: mmc1-board {
+ atmel,pins =
+ <3 11 0x0 0x5 /* PD11 gpio CD pin pull up and deglitch */
+ 3 29 0x0 0x1>; /* PD29 gpio WP pin pull up */
+ };
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 82508d68aa7e..e9efb34f4379 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -84,6 +84,15 @@
reg = <0xfffffe10 0x10>;
};
+ mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+ interrupts = <12 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
tcb0: timer@f8008000 {
compatible = "atmel,at91sam9x5-tcb";
reg = <0xf8008000 0x100>;
@@ -102,50 +111,186 @@
interrupts = <20 4 0>;
};
- pioA: gpio@fffff400 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
- pioB: gpio@fffff600 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ atmel,mux-mask = <
+ /* A B C */
+ 0xffffffff 0xffe07983 0x00000000 /* pioA */
+ 0x00040000 0x00047e0f 0x00000000 /* pioB */
+ 0xfdffffff 0x07c00000 0xb83fffff /* pioC */
+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
+ >;
- pioC: gpio@fffff800 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <0 9 0x1 0x0 /* PA9 periph A */
+ 0 10 0x1 0x1>; /* PA10 periph with pullup */
+ };
+ };
- pioD: gpio@fffffa00 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <0 1 0x1 0x1 /* PA1 periph A with pullup */
+ 0 0 0x1 0x0>; /* PA0 periph A */
+ };
+
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins =
+ <0 2 0x1 0x0>; /* PA2 periph A */
+ };
+
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins =
+ <0 3 0x1 0x0>; /* PA3 periph A */
+ };
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <0 6 0x1 0x1 /* PA6 periph A with pullup */
+ 0 5 0x1 0x0>; /* PA5 periph A */
+ };
+ };
+
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ atmel,pins =
+ <0 8 0x1 0x1 /* PA8 periph A with pullup */
+ 0 7 0x1 0x0>; /* PA7 periph A */
+ };
+
+ pinctrl_usart2_rts: usart2_rts-0 {
+ atmel,pins =
+ <1 0 0x2 0x0>; /* PB0 periph B */
+ };
+
+ pinctrl_usart2_cts: usart2_cts-0 {
+ atmel,pins =
+ <1 1 0x2 0x0>; /* PB1 periph B */
+ };
+ };
+
+ usart3 {
+ pinctrl_usart3: usart3-0 {
+ atmel,pins =
+ <2 23 0x2 0x1 /* PC23 periph B with pullup */
+ 2 22 0x2 0x0>; /* PC22 periph B */
+ };
+
+ pinctrl_usart3_rts: usart3_rts-0 {
+ atmel,pins =
+ <2 24 0x2 0x0>; /* PC24 periph B */
+ };
+
+ pinctrl_usart3_cts: usart3_cts-0 {
+ atmel,pins =
+ <2 25 0x2 0x0>; /* PC25 periph B */
+ };
+ };
+
+ uart0 {
+ pinctrl_uart0: uart0-0 {
+ atmel,pins =
+ <2 9 0x3 0x1 /* PC9 periph C with pullup */
+ 2 8 0x3 0x0>; /* PC8 periph C */
+ };
+ };
+
+ uart1 {
+ pinctrl_uart1: uart1-0 {
+ atmel,pins =
+ <2 16 0x3 0x1 /* PC17 periph C with pullup */
+ 2 17 0x3 0x0>; /* PC16 periph C */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <3 5 0x0 0x1 /* PD5 gpio RDY pin pull_up*/
+ 3 4 0x0 0x1>; /* PD4 gpio enable pin pull_up */
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0_slot0_clk_cmd_dat0: mmc0_slot0_clk_cmd_dat0-0 {
+ atmel,pins =
+ <0 17 0x1 0x0 /* PA17 periph A */
+ 0 16 0x1 0x1 /* PA16 periph A with pullup */
+ 0 15 0x1 0x1>; /* PA15 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 18 0x1 0x1 /* PA18 periph A with pullup */
+ 0 19 0x1 0x1 /* PA19 periph A with pullup */
+ 0 20 0x1 0x1>; /* PA20 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat4_7: mmc0_slot0_dat4_7-0 {
+ atmel,pins =
+ <0 11 0x2 0x1 /* PA11 periph B with pullup */
+ 0 12 0x2 0x1 /* PA12 periph B with pullup */
+ 0 13 0x2 0x1 /* PA13 periph B with pullup */
+ 0 14 0x2 0x1>; /* PA14 periph B with pullup */
+ };
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
dbgu: serial@fffff200 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffff200 0x200>;
interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
status = "disabled";
};
@@ -155,6 +300,8 @@
interrupts = <5 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
};
@@ -164,6 +311,8 @@
interrupts = <6 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
};
@@ -173,6 +322,8 @@
interrupts = <7 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
};
@@ -182,6 +333,8 @@
interrupts = <8 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart3>;
status = "disabled";
};
@@ -215,6 +368,8 @@
>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
gpios = <&pioD 5 0
&pioD 4 0
0
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index 912b2c283d6f..0376bf4fd66b 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -45,6 +45,28 @@
i2c1: i2c@f8014000 {
status = "okay";
};
+
+ mmc0: mmc@f0008000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc0
+ &pinctrl_mmc0_slot0_clk_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioA 7 0>;
+ };
+ };
+
+ pinctrl@fffff400 {
+ mmc0 {
+ pinctrl_board_mmc0: mmc0-board {
+ atmel,pins =
+ <0 7 0x0 0x5>; /* PA7 gpio CD pin pull up and deglitch */
+ };
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9x25.dtsi b/arch/arm/boot/dts/at91sam9x25.dtsi
new file mode 100644
index 000000000000..54eb33ba6d22
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x25.dtsi
@@ -0,0 +1,49 @@
+/*
+ * at91sam9x25.dtsi - Device Tree Include file for AT91SAM9X25 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9X25 SoC";
+ compatible = "atmel, at91sam9x25, atmel,at91sam9x5";
+
+ ahb {
+ apb {
+ pinctrl@fffff400 {
+ atmel,mux-mask = <
+ /* A B C */
+ 0xffffffff 0xffe03fff 0xc000001c /* pioA */
+ 0x0007ffff 0x00047e3f 0x00000000 /* pioB */
+ 0x80000000 0xfffd0000 0xb83fffff /* pioC */
+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
+ >;
+
+ macb1 {
+ pinctrl_macb1_rmii: macb1_rmii-0 {
+ atmel,pins =
+ <2 16 0x2 0x0 /* PC16 periph B */
+ 2 18 0x2 0x0 /* PC18 periph B */
+ 2 19 0x2 0x0 /* PC19 periph B */
+ 2 20 0x2 0x0 /* PC20 periph B */
+ 2 21 0x2 0x0 /* PC21 periph B */
+ 2 27 0x2 0x0 /* PC27 periph B */
+ 2 28 0x2 0x0 /* PC28 periph B */
+ 2 29 0x2 0x0 /* PC29 periph B */
+ 2 30 0x2 0x0 /* PC30 periph B */
+ 2 31 0x2 0x0>; /* PC31 periph B */
+ };
+ };
+ };
+
+ macb1: ethernet@f8030000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb1_rmii>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9x25ek.dts b/arch/arm/boot/dts/at91sam9x25ek.dts
new file mode 100644
index 000000000000..af907eaa1f25
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x25ek.dts
@@ -0,0 +1,16 @@
+/*
+ * at91sam9x25ek.dts - Device Tree file for AT91SAM9X25-EK board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x25.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9G25-EK";
+ compatible = "atmel,at91sam9x25ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi
new file mode 100644
index 000000000000..fb102d6126ce
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x35.dtsi
@@ -0,0 +1,28 @@
+/*
+ * at91sam9x35.dtsi - Device Tree Include file for AT91SAM9X35 SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/include/ "at91sam9x5.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9X35 SoC";
+ compatible = "atmel, at91sam9x35, atmel,at91sam9x5";
+
+ ahb {
+ apb {
+ pinctrl@fffff400 {
+ atmel,mux-mask = <
+ /* A B C */
+ 0xffffffff 0xffe03fff 0xc000000c /* pioA */
+ 0x000406ff 0x00047e3f 0x00000000 /* pioB */
+ 0xfdffffff 0x00000000 0xb83fffff /* pioC */
+ 0x003fffff 0x003f8000 0x00000000 /* pioD */
+ >;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9x35ek.dts b/arch/arm/boot/dts/at91sam9x35ek.dts
new file mode 100644
index 000000000000..5ccb607b5414
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x35ek.dts
@@ -0,0 +1,16 @@
+/*
+ * at91sam9x35ek.dts - Device Tree file for AT91SAM9X35-EK board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9x35.dtsi"
+/include/ "at91sam9x5ek.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9X35-EK";
+ compatible = "atmel,at91sam9x35ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 03fc136421c5..7ee49e8daf98 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -111,50 +111,244 @@
interrupts = <21 4 0>;
};
- pioA: gpio@fffff400 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
- };
+ pinctrl@fffff400 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ ranges = <0xfffff400 0xfffff400 0x800>;
+
+ /* shared pinctrl settings */
+ dbgu {
+ pinctrl_dbgu: dbgu-0 {
+ atmel,pins =
+ <0 9 0x1 0x0 /* PA9 periph A */
+ 0 10 0x1 0x1>; /* PA10 periph A with pullup */
+ };
+ };
- pioB: gpio@fffff600 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
- interrupts = <2 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ usart0 {
+ pinctrl_usart0: usart0-0 {
+ atmel,pins =
+ <0 0 0x1 0x1 /* PA0 periph A with pullup */
+ 0 1 0x1 0x0>; /* PA1 periph A */
+ };
+
+ pinctrl_usart0_rts: usart0_rts-0 {
+ atmel,pins =
+ <0 2 0x1 0x0>; /* PA2 periph A */
+ };
+
+ pinctrl_usart0_cts: usart0_cts-0 {
+ atmel,pins =
+ <0 3 0x1 0x0>; /* PA3 periph A */
+ };
+ };
+
+ usart1 {
+ pinctrl_usart1: usart1-0 {
+ atmel,pins =
+ <0 5 0x1 0x1 /* PA5 periph A with pullup */
+ 0 6 0x1 0x0>; /* PA6 periph A */
+ };
+
+ pinctrl_usart1_rts: usart1_rts-0 {
+ atmel,pins =
+ <3 27 0x3 0x0>; /* PC27 periph C */
+ };
+
+ pinctrl_usart1_cts: usart1_cts-0 {
+ atmel,pins =
+ <3 28 0x3 0x0>; /* PC28 periph C */
+ };
+ };
+
+ usart2 {
+ pinctrl_usart2: usart2-0 {
+ atmel,pins =
+ <0 7 0x1 0x1 /* PA7 periph A with pullup */
+ 0 8 0x1 0x0>; /* PA8 periph A */
+ };
+
+ pinctrl_uart2_rts: uart2_rts-0 {
+ atmel,pins =
+ <0 0 0x2 0x0>; /* PB0 periph B */
+ };
+
+ pinctrl_uart2_cts: uart2_cts-0 {
+ atmel,pins =
+ <0 1 0x2 0x0>; /* PB1 periph B */
+ };
+ };
+
+ usart3 {
+ pinctrl_uart3: usart3-0 {
+ atmel,pins =
+ <3 23 0x2 0x1 /* PC22 periph B with pullup */
+ 3 23 0x2 0x0>; /* PC23 periph B */
+ };
+
+ pinctrl_usart3_rts: usart3_rts-0 {
+ atmel,pins =
+ <3 24 0x2 0x0>; /* PC24 periph B */
+ };
+
+ pinctrl_usart3_cts: usart3_cts-0 {
+ atmel,pins =
+ <3 25 0x2 0x0>; /* PC25 periph B */
+ };
+ };
+
+ uart0 {
+ pinctrl_uart0: uart0-0 {
+ atmel,pins =
+ <3 8 0x3 0x0 /* PC8 periph C */
+ 3 9 0x3 0x1>; /* PC9 periph C with pullup */
+ };
+ };
+
+ uart1 {
+ pinctrl_uart1: uart1-0 {
+ atmel,pins =
+ <3 16 0x3 0x0 /* PC16 periph C */
+ 3 17 0x3 0x1>; /* PC17 periph C with pullup */
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand-0 {
+ atmel,pins =
+ <3 4 0x0 0x1 /* PD5 gpio RDY pin pull_up */
+ 3 5 0x0 0x1>; /* PD4 gpio enable pin pull_up */
+ };
+ };
+
+ macb0 {
+ pinctrl_macb0_rmii: macb0_rmii-0 {
+ atmel,pins =
+ <1 0 0x1 0x0 /* PB0 periph A */
+ 1 1 0x1 0x0 /* PB1 periph A */
+ 1 2 0x1 0x0 /* PB2 periph A */
+ 1 3 0x1 0x0 /* PB3 periph A */
+ 1 4 0x1 0x0 /* PB4 periph A */
+ 1 5 0x1 0x0 /* PB5 periph A */
+ 1 6 0x1 0x0 /* PB6 periph A */
+ 1 7 0x1 0x0 /* PB7 periph A */
+ 1 9 0x1 0x0 /* PB9 periph A */
+ 1 10 0x1 0x0>; /* PB10 periph A */
+ };
+
+ pinctrl_macb0_rmii_mii: macb0_rmii_mii-0 {
+ atmel,pins =
+ <1 8 0x1 0x0 /* PA8 periph A */
+ 1 11 0x1 0x0 /* PA11 periph A */
+ 1 12 0x1 0x0 /* PA12 periph A */
+ 1 13 0x1 0x0 /* PA13 periph A */
+ 1 14 0x1 0x0 /* PA14 periph A */
+ 1 15 0x1 0x0 /* PA15 periph A */
+ 1 16 0x1 0x0 /* PA16 periph A */
+ 1 17 0x1 0x0>; /* PA17 periph A */
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0_slot0_clk_cmd_dat0: mmc0_slot0_clk_cmd_dat0-0 {
+ atmel,pins =
+ <0 17 0x1 0x0 /* PA17 periph A */
+ 0 16 0x1 0x1 /* PA16 periph A with pullup */
+ 0 15 0x1 0x1>; /* PA15 periph A with pullup */
+ };
+
+ pinctrl_mmc0_slot0_dat1_3: mmc0_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 18 0x1 0x1 /* PA18 periph A with pullup */
+ 0 19 0x1 0x1 /* PA19 periph A with pullup */
+ 0 20 0x1 0x1>; /* PA20 periph A with pullup */
+ };
+ };
+
+ mmc1 {
+ pinctrl_mmc1_slot0_clk_cmd_dat0: mmc1_slot0_clk_cmd_dat0-0 {
+ atmel,pins =
+ <0 13 0x2 0x0 /* PA13 periph B */
+ 0 12 0x2 0x1 /* PA12 periph B with pullup */
+ 0 11 0x2 0x1>; /* PA11 periph B with pullup */
+ };
+
+ pinctrl_mmc1_slot0_dat1_3: mmc1_slot0_dat1_3-0 {
+ atmel,pins =
+ <0 2 0x2 0x1 /* PA2 periph B with pullup */
+ 0 3 0x2 0x1 /* PA3 periph B with pullup */
+ 0 4 0x2 0x1>; /* PA4 periph B with pullup */
+ };
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x200>;
+ interrupts = <2 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ #gpio-lines = <19>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x200>;
+ interrupts = <3 4 1>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ #gpio-lines = <22>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
};
- pioC: gpio@fffff800 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ mmc0: mmc@f0008000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf0008000 0x600>;
+ interrupts = <12 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
};
- pioD: gpio@fffffa00 {
- compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
- reg = <0xfffffa00 0x100>;
- interrupts = <3 4 1>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- #interrupt-cells = <2>;
+ mmc1: mmc@f000c000 {
+ compatible = "atmel,hsmci";
+ reg = <0xf000c000 0x600>;
+ interrupts = <26 4 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
};
dbgu: serial@fffff200 {
compatible = "atmel,at91sam9260-usart";
reg = <0xfffff200 0x200>;
interrupts = <1 4 7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dbgu>;
status = "disabled";
};
@@ -164,6 +358,8 @@
interrupts = <5 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart0>;
status = "disabled";
};
@@ -173,6 +369,8 @@
interrupts = <6 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart1>;
status = "disabled";
};
@@ -182,6 +380,8 @@
interrupts = <7 4 5>;
atmel,use-dma-rx;
atmel,use-dma-tx;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usart2>;
status = "disabled";
};
@@ -189,6 +389,8 @@
compatible = "cdns,at32ap7000-macb", "cdns,macb";
reg = <0xf802c000 0x100>;
interrupts = <24 4 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb0_rmii>;
status = "disabled";
};
@@ -273,6 +475,8 @@
>;
atmel,nand-addr-offset = <21>;
atmel,nand-cmd-offset = <22>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nand>;
gpios = <&pioD 5 0
&pioD 4 0
0
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
new file mode 100644
index 000000000000..8a7cf1d9cf5d
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -0,0 +1,101 @@
+/*
+ * at91sam9x5ek.dtsi - Device Tree file for AT91SAM9x5CM Base board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/include/ "at91sam9x5cm.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9X5-EK";
+ compatible = "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=ubifs ubi.mtd=1 root=ubi0:rootfs";
+ };
+
+ ahb {
+ apb {
+ mmc0: mmc@f0008000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc0
+ &pinctrl_mmc0_slot0_clk_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 15 0>;
+ };
+ };
+
+ mmc1: mmc@f000c000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc1
+ &pinctrl_mmc1_slot0_clk_cmd_dat0
+ &pinctrl_mmc1_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 14 0>;
+ };
+ };
+
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ usart0: serial@f801c000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@f802c000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ i2c0: i2c@f8010000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@f8014000 {
+ status = "okay";
+ };
+
+ i2c2: i2c@f8018000 {
+ status = "okay";
+ };
+
+ pinctrl@fffff400 {
+ mmc0 {
+ pinctrl_board_mmc0: mmc0-board {
+ atmel,pins =
+ <3 15 0x0 0x5>; /* PD15 gpio CD pin pull up and deglitch */
+ };
+ };
+
+ mmc1 {
+ pinctrl_board_mmc1: mmc1-board {
+ atmel,pins =
+ <3 14 0x0 0x5>; /* PD14 gpio CD pin pull up and deglitch */
+ };
+ };
+ };
+ };
+
+ usb0: ohci@00600000 {
+ status = "okay";
+ num-ports = <2>;
+ atmel,vbus-gpio = <&pioD 19 1
+ &pioD 20 1
+ >;
+ };
+
+ usb1: ehci@00700000 {
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/pm9g45.dts b/arch/arm/boot/dts/pm9g45.dts
new file mode 100644
index 000000000000..387fedb58988
--- /dev/null
+++ b/arch/arm/boot/dts/pm9g45.dts
@@ -0,0 +1,165 @@
+/*
+ * pm9g45.dts - Device Tree file for Ronetix pm9g45 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g45.dtsi"
+
+/ {
+ model = "Ronetix pm9g45";
+ compatible = "ronetix,pm9g45", "atmel,at91sam9g45", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x70000000 0x8000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@ffffee00 {
+ status = "okay";
+ };
+
+ pinctrl@fffff200 {
+
+ board {
+ pinctrl_board_nand: nand0-board {
+ atmel,pins =
+ <3 3 0x0 0x1 /* PD3 gpio RDY pin pull_up*/
+ 2 14 0x0 0x1>; /* PC14 gpio enable pin pull_up */
+ };
+ };
+
+ mmc {
+ pinctrl_board_mmc: mmc0-board {
+ atmel,pins =
+ <3 6 0x0 0x5>; /* PD6 gpio CD pin pull_up and deglitch */
+ };
+ };
+ };
+
+ mmc0: mmc@fff80000 {
+ pinctrl-0 = <
+ &pinctrl_board_mmc
+ &pinctrl_mmc0_slot0_clk_cmd_dat0
+ &pinctrl_mmc0_slot0_dat1_3>;
+ status = "okay";
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ cd-gpios = <&pioD 6 0>;
+ };
+ };
+
+ macb0: ethernet@fffbc000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ pinctrl-0 = <&pinctrl_board_nand>;
+
+ gpios = <&pioD 3 0
+ &pioC 14 0
+ 0
+ >;
+
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x1A0000>;
+ };
+
+ kernel@200000 {
+ label = "bareboxenv2";
+ reg = <0x200000 0x300000>;
+ };
+
+ kernel@500000 {
+ label = "root";
+ reg = <0x500000 0x400000>;
+ };
+
+ data@900000 {
+ label = "data";
+ reg = <0x900000 0x8340000>;
+ };
+ };
+
+ usb0: ohci@00700000 {
+ status = "okay";
+ num-ports = <2>;
+ };
+
+ usb1: ehci@00800000 {
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led0 {
+ label = "led0";
+ gpios = <&pioD 0 1>;
+ linux,default-trigger = "nand-disk";
+ };
+
+ led1 {
+ label = "led1";
+ gpios = <&pioD 31 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ right {
+ label = "SW4";
+ gpios = <&pioE 7 1>;
+ linux,code = <106>;
+ };
+
+ up {
+ label = "SW3";
+ gpios = <&pioE 8 1>;
+ linux,code = <103>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear1310-evb.dts b/arch/arm/boot/dts/spear1310-evb.dts
index dd4358bc26e2..2e4c5727468e 100644
--- a/arch/arm/boot/dts/spear1310-evb.dts
+++ b/arch/arm/boot/dts/spear1310-evb.dts
@@ -181,6 +181,10 @@
status = "okay";
};
+ gpio@d8400000 {
+ status = "okay";
+ };
+
i2c0: i2c@e0280000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/spear1310.dtsi b/arch/arm/boot/dts/spear1310.dtsi
index 419ea7413d23..7cd25eb4f8e0 100644
--- a/arch/arm/boot/dts/spear1310.dtsi
+++ b/arch/arm/boot/dts/spear1310.dtsi
@@ -70,6 +70,12 @@
status = "disabled";
};
+ pinmux: pinmux@e0700000 {
+ compatible = "st,spear1310-pinmux";
+ reg = <0xe0700000 0x1000>;
+ #gpio-range-cells = <2>;
+ };
+
spi1: spi@5d400000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0x5d400000 0x1000>;
@@ -179,6 +185,27 @@
thermal@e07008c4 {
st,thermal-flags = <0x7000>;
};
+
+ gpiopinctrl: gpio@d8400000 {
+ compatible = "st,spear-plgpio";
+ reg = <0xd8400000 0x1000>;
+ interrupts = <0 100 0x4>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinmux 0 246>;
+ status = "disabled";
+
+ st-plgpio,ngpio = <246>;
+ st-plgpio,enb-reg = <0xd0>;
+ st-plgpio,wdata-reg = <0x90>;
+ st-plgpio,dir-reg = <0xb0>;
+ st-plgpio,ie-reg = <0x30>;
+ st-plgpio,rdata-reg = <0x70>;
+ st-plgpio,mis-reg = <0x10>;
+ st-plgpio,eit-reg = <0x50>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/spear1340-evb.dts b/arch/arm/boot/dts/spear1340-evb.dts
index c9a54e06fb68..045f7123ffac 100644
--- a/arch/arm/boot/dts/spear1340-evb.dts
+++ b/arch/arm/boot/dts/spear1340-evb.dts
@@ -193,6 +193,10 @@
status = "okay";
};
+ gpio@e2800000 {
+ status = "okay";
+ };
+
i2c0: i2c@e0280000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/spear1340.dtsi b/arch/arm/boot/dts/spear1340.dtsi
index d71fe2a68f09..6c09eb0a1b2b 100644
--- a/arch/arm/boot/dts/spear1340.dtsi
+++ b/arch/arm/boot/dts/spear1340.dtsi
@@ -24,6 +24,12 @@
status = "disabled";
};
+ pinmux: pinmux@e0700000 {
+ compatible = "st,spear1340-pinmux";
+ reg = <0xe0700000 0x1000>;
+ #gpio-range-cells = <2>;
+ };
+
spi1: spi@5d400000 {
compatible = "arm,pl022", "arm,primecell";
reg = <0x5d400000 0x1000>;
@@ -51,6 +57,26 @@
thermal@e07008c4 {
st,thermal-flags = <0x2a00>;
};
+
+ gpiopinctrl: gpio@e2800000 {
+ compatible = "st,spear-plgpio";
+ reg = <0xe2800000 0x1000>;
+ interrupts = <0 107 0x4>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinmux 0 252>;
+ status = "disabled";
+
+ st-plgpio,ngpio = <250>;
+ st-plgpio,wdata-reg = <0x40>;
+ st-plgpio,dir-reg = <0x00>;
+ st-plgpio,ie-reg = <0x80>;
+ st-plgpio,rdata-reg = <0x20>;
+ st-plgpio,mis-reg = <0xa0>;
+ st-plgpio,eit-reg = <0x60>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi
index 62fc4fb3e5f9..930303e48df9 100644
--- a/arch/arm/boot/dts/spear310.dtsi
+++ b/arch/arm/boot/dts/spear310.dtsi
@@ -22,9 +22,10 @@
0xb0000000 0xb0000000 0x10000000
0xd0000000 0xd0000000 0x30000000>;
- pinmux@b4000000 {
+ pinmux: pinmux@b4000000 {
compatible = "st,spear310-pinmux";
reg = <0xb4000000 0x1000>;
+ #gpio-range-cells = <2>;
};
fsmc: flash@44000000 {
@@ -75,6 +76,25 @@
reg = <0xb2200000 0x1000>;
status = "disabled";
};
+
+ gpiopinctrl: gpio@b4000000 {
+ compatible = "st,spear-plgpio";
+ reg = <0xb4000000 0x1000>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinmux 0 102>;
+ status = "disabled";
+
+ st-plgpio,ngpio = <102>;
+ st-plgpio,enb-reg = <0x10>;
+ st-plgpio,wdata-reg = <0x20>;
+ st-plgpio,dir-reg = <0x30>;
+ st-plgpio,ie-reg = <0x50>;
+ st-plgpio,rdata-reg = <0x40>;
+ st-plgpio,mis-reg = <0x60>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts
index 082328bd64ab..ad4bfc68ee05 100644
--- a/arch/arm/boot/dts/spear320-evb.dts
+++ b/arch/arm/boot/dts/spear320-evb.dts
@@ -164,6 +164,10 @@
status = "okay";
};
+ gpio@b3000000 {
+ status = "okay";
+ };
+
i2c0: i2c@d0180000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi
index 1f49d69595a0..67d7ada71275 100644
--- a/arch/arm/boot/dts/spear320.dtsi
+++ b/arch/arm/boot/dts/spear320.dtsi
@@ -21,9 +21,10 @@
ranges = <0x40000000 0x40000000 0x80000000
0xd0000000 0xd0000000 0x30000000>;
- pinmux@b3000000 {
+ pinmux: pinmux@b3000000 {
compatible = "st,spear320-pinmux";
reg = <0xb3000000 0x1000>;
+ #gpio-range-cells = <2>;
};
clcd@90000000 {
@@ -90,6 +91,26 @@
reg = <0xa4000000 0x1000>;
status = "disabled";
};
+
+ gpiopinctrl: gpio@b3000000 {
+ compatible = "st,spear-plgpio";
+ reg = <0xb3000000 0x1000>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinmux 0 102>;
+ status = "disabled";
+
+ st-plgpio,ngpio = <102>;
+ st-plgpio,enb-reg = <0x24>;
+ st-plgpio,wdata-reg = <0x34>;
+ st-plgpio,dir-reg = <0x44>;
+ st-plgpio,ie-reg = <0x64>;
+ st-plgpio,rdata-reg = <0x54>;
+ st-plgpio,mis-reg = <0x84>;
+ st-plgpio,eit-reg = <0x94>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index b1497c7d7d68..df7f2270fc91 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -73,8 +73,8 @@
pinmux: pinmux {
compatible = "nvidia,tegra30-pinmux";
- reg = <0x70000868 0xd0 /* Pad control registers */
- 0x70003000 0x3e0>; /* Mux registers */
+ reg = <0x70000868 0xd4 /* Pad control registers */
+ 0x70003000 0x3e4>; /* Mux registers */
};
serial@70006000 {
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index df13a3ffff35..9d2d3ba339ff 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -162,7 +162,6 @@ static struct clock_event_device sp804_clockevent = {
.set_mode = sp804_set_mode,
.set_next_event = sp804_set_next_event,
.rating = 300,
- .cpumask = cpu_all_mask,
};
static struct irqaction sp804_timer_irq = {
@@ -185,6 +184,7 @@ void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
evt->name = name;
evt->irq = irq;
+ evt->cpumask = cpu_possible_mask;
setup_irq(irq, &sp804_timer_irq);
clockevents_config_and_register(evt, rate, 0xf, 0xffffffff);
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
index 67bc571ed0c3..b175577d7abb 100644
--- a/arch/arm/configs/at91_dt_defconfig
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -111,6 +111,7 @@ CONFIG_I2C=y
CONFIG_I2C_GPIO=y
CONFIG_SPI=y
CONFIG_SPI_ATMEL=y
+CONFIG_PINCTRL_AT91=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_AT91SAM9X_WATCHDOG=y
diff --git a/arch/arm/include/asm/hardware/sp810.h b/arch/arm/include/asm/hardware/sp810.h
index 6b9b077d86b3..afd7e916472f 100644
--- a/arch/arm/include/asm/hardware/sp810.h
+++ b/arch/arm/include/asm/hardware/sp810.h
@@ -56,6 +56,8 @@
#define SCCTRL_TIMEREN1SEL_REFCLK (0 << 17)
#define SCCTRL_TIMEREN1SEL_TIMCLK (1 << 17)
+#define SCCTRL_TIMERENnSEL_SHIFT(n) (15 + ((n) * 2))
+
static inline void sysctl_soft_reset(void __iomem *base)
{
/* switch to slow mode */
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 043624219b55..e34c1bdb804d 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -494,8 +494,17 @@ endif
comment "Generic Board Type"
+config MACH_AT91RM9200_DT
+ bool "Atmel AT91RM9200 Evaluation Kits with device-tree support"
+ depends on SOC_AT91RM9200
+ select USE_OF
+ help
+ Select this if you want to experiment device-tree with
+ an Atmel RM9200 Evaluation Kit.
+
config MACH_AT91SAM_DT
bool "Atmel AT91SAM Evaluation Kits with device-tree support"
+ depends on SOC_AT91SAM9
select USE_OF
help
Select this if you want to experiment device-tree with
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 3bb7a51efc9d..b38a1dcb79b8 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -88,6 +88,7 @@ obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
# AT91SAM board with device-tree
+obj-$(CONFIG_MACH_AT91RM9200_DT) += board-rm9200-dt.o
obj-$(CONFIG_MACH_AT91SAM_DT) += board-dt.o
# AT91X40 board-specific support
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 5269825194a8..6cceb42a4c33 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -194,6 +194,24 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
CLKDEV_CON_ID("pioD", &pioD_clk),
+ /* usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fffc0000.serial", &usart0_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffc4000.serial", &usart1_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffc8000.serial", &usart2_clk),
+ CLKDEV_CON_DEV_ID("usart", "fffcc000.serial", &usart3_clk),
+ /* tc lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
+ CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "fffa4000.timer", &tc3_clk),
+ CLKDEV_CON_DEV_ID("t1_clk", "fffa4000.timer", &tc4_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "fffa4000.timer", &tc5_clk),
+ CLKDEV_CON_DEV_ID("hclk", "300000.ohci", &ohci_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioD_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
@@ -361,10 +379,10 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
0 /* Advanced Interrupt Controller (IRQ6) */
};
-struct at91_init_soc __initdata at91rm9200_soc = {
+AT91_SOC_START(rm9200)
.map_io = at91rm9200_map_io,
.default_irq_priority = at91rm9200_default_irq_priority,
.ioremap_registers = at91rm9200_ioremap_registers,
.register_clocks = at91rm9200_register_clocks,
.init = at91rm9200_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 1e122bcd7845..3cee0e6ea7c3 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -68,7 +68,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data)
/* Enable overcurrent notification */
for (i = 0; i < data->ports; i++) {
- if (data->overcurrent_pin[i])
+ if (gpio_is_valid(data->overcurrent_pin[i]))
at91_set_gpio_input(data->overcurrent_pin[i], 1);
}
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index aaa443b48c91..cafe98836c8a 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -24,6 +24,9 @@
#include <linux/irq.h>
#include <linux/clockchips.h>
#include <linux/export.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/mach/time.h>
@@ -91,7 +94,8 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
static struct irqaction at91rm9200_timer_irq = {
.name = "at91_tick",
.flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = at91rm9200_timer_interrupt
+ .handler = at91rm9200_timer_interrupt,
+ .irq = NR_IRQS_LEGACY + AT91_ID_SYS,
};
static cycle_t read_clk32k(struct clocksource *cs)
@@ -179,8 +183,60 @@ static struct clock_event_device clkevt = {
void __iomem *at91_st_base;
EXPORT_SYMBOL_GPL(at91_st_base);
+#ifdef CONFIG_OF
+static struct of_device_id at91rm9200_st_timer_ids[] = {
+ { .compatible = "atmel,at91rm9200-st" },
+ { /* sentinel */ }
+};
+
+static int __init of_at91rm9200_st_init(void)
+{
+ struct device_node *np;
+ int ret;
+
+ np = of_find_matching_node(NULL, at91rm9200_st_timer_ids);
+ if (!np)
+ goto err;
+
+ at91_st_base = of_iomap(np, 0);
+ if (!at91_st_base)
+ goto node_err;
+
+ /* Get the interrupts property */
+ ret = irq_of_parse_and_map(np, 0);
+ if (!ret)
+ goto ioremap_err;
+ at91rm9200_timer_irq.irq = ret;
+
+ of_node_put(np);
+
+ return 0;
+
+ioremap_err:
+ iounmap(at91_st_base);
+node_err:
+ of_node_put(np);
+err:
+ return -EINVAL;
+}
+#else
+static int __init of_at91rm9200_st_init(void)
+{
+ return -EINVAL;
+}
+#endif
+
void __init at91rm9200_ioremap_st(u32 addr)
{
+#ifdef CONFIG_OF
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, at91rm9200_st_timer_ids);
+ if (np) {
+ of_node_put(np);
+ return;
+ }
+#endif
at91_st_base = ioremap(addr, 256);
if (!at91_st_base)
panic("Impossible to ioremap ST\n");
@@ -191,13 +247,16 @@ void __init at91rm9200_ioremap_st(u32 addr)
*/
void __init at91rm9200_timer_init(void)
{
+ /* For device tree enabled device: initialize here */
+ of_at91rm9200_st_init();
+
/* Disable all timer interrupts, and clear any pending ones */
at91_st_write(AT91_ST_IDR,
AT91_ST_PITS | AT91_ST_WDOVF | AT91_ST_RTTINC | AT91_ST_ALMS);
at91_st_read(AT91_ST_SR);
/* Make IRQs happen for the system timer */
- setup_irq(NR_IRQS_LEGACY + AT91_ID_SYS, &at91rm9200_timer_irq);
+ setup_irq(at91rm9200_timer_irq.irq, &at91rm9200_timer_irq);
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
* directly for the clocksource and all clockevents, after adjusting
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index f8202615f4a8..c9e029e44d8a 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -230,11 +230,15 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
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),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
@@ -390,10 +394,10 @@ static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
0, /* Advanced Interrupt Controller */
};
-struct at91_init_soc __initdata at91sam9260_soc = {
+AT91_SOC_START(sam9260)
.map_io = at91sam9260_map_io,
.default_irq_priority = at91sam9260_default_irq_priority,
.ioremap_registers = at91sam9260_ioremap_registers,
.register_clocks = at91sam9260_register_clocks,
.init = at91sam9260_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index aa1e58729885..414bd855fb0c 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -72,7 +72,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data)
/* Enable overcurrent notification */
for (i = 0; i < data->ports; i++) {
- if (data->overcurrent_pin[i])
+ if (gpio_is_valid(data->overcurrent_pin[i]))
at91_set_gpio_input(data->overcurrent_pin[i], 1);
}
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 04295c04b3e0..4d262f346fd9 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -334,10 +334,10 @@ static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
0, /* Advanced Interrupt Controller */
};
-struct at91_init_soc __initdata at91sam9261_soc = {
+AT91_SOC_START(sam9261)
.map_io = at91sam9261_map_io,
.default_irq_priority = at91sam9261_default_irq_priority,
.ioremap_registers = at91sam9261_ioremap_registers,
.register_clocks = at91sam9261_register_clocks,
.init = at91sam9261_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index b9487696b7be..cd604aad8e96 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -72,7 +72,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data)
/* Enable overcurrent notification */
for (i = 0; i < data->ports; i++) {
- if (data->overcurrent_pin[i])
+ if (gpio_is_valid(data->overcurrent_pin[i]))
at91_set_gpio_input(data->overcurrent_pin[i], 1);
}
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index d6f9c23927c4..ed390f6fa232 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -211,7 +211,14 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
@@ -365,10 +372,10 @@ static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
0, /* Advanced Interrupt Controller (IRQ1) */
};
-struct at91_init_soc __initdata at91sam9263_soc = {
+AT91_SOC_START(sam9263)
.map_io = at91sam9263_map_io,
.default_irq_priority = at91sam9263_default_irq_priority,
.ioremap_registers = at91sam9263_ioremap_registers,
.register_clocks = at91sam9263_register_clocks,
.init = at91sam9263_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index cb85da2eccea..9c61e59a2104 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -78,7 +78,7 @@ void __init at91_add_device_usbh(struct at91_usbh_data *data)
/* Enable overcurrent notification */
for (i = 0; i < data->ports; i++) {
- if (data->overcurrent_pin[i])
+ if (gpio_is_valid(data->overcurrent_pin[i]))
at91_set_gpio_input(data->overcurrent_pin[i], 1);
}
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 84af1b506d92..c5c2acc4bf22 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -256,10 +256,18 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
+ 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),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk),
+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk),
+
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
@@ -409,10 +417,10 @@ static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
0, /* Advanced Interrupt Controller (IRQ0) */
};
-struct at91_init_soc __initdata at91sam9g45_soc = {
+AT91_SOC_START(sam9g45)
.map_io = at91sam9g45_map_io,
.default_irq_priority = at91sam9g45_default_irq_priority,
.ioremap_registers = at91sam9g45_ioremap_registers,
.register_clocks = at91sam9g45_register_clocks,
.init = at91sam9g45_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index b1596072dcc2..fcd233cb33d2 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -1841,8 +1841,8 @@ static struct resource sha_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91SAM9G45_ID_AESTDESSHA,
- .end = AT91SAM9G45_ID_AESTDESSHA,
+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
.flags = IORESOURCE_IRQ,
},
};
@@ -1874,8 +1874,8 @@ static struct resource tdes_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91SAM9G45_ID_AESTDESSHA,
- .end = AT91SAM9G45_ID_AESTDESSHA,
+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
.flags = IORESOURCE_IRQ,
},
};
@@ -1910,8 +1910,8 @@ static struct resource aes_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91SAM9G45_ID_AESTDESSHA,
- .end = AT91SAM9G45_ID_AESTDESSHA,
+ .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
+ .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index 732d3d3f4ec5..70b3a99244ab 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -168,13 +168,14 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
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_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
- CLKDEV_CON_ID("pioD", &pioCD_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),
+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
/* additional fake clock for macb_hclk */
CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
@@ -223,13 +224,10 @@ static void __init at91sam9n12_map_io(void)
void __init at91sam9n12_initialize(void)
{
at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
-
- /* Register GPIO subsystem (using DT) */
- at91_gpio_init(NULL, 0);
}
-struct at91_init_soc __initdata at91sam9n12_soc = {
+AT91_SOC_START(sam9n12)
.map_io = at91sam9n12_map_io,
.register_clocks = at91sam9n12_register_clocks,
.init = at91sam9n12_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index 72e908412222..cbe72e44c13f 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -338,10 +338,10 @@ static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
0, /* Advanced Interrupt Controller */
};
-struct at91_init_soc __initdata at91sam9rl_soc = {
+AT91_SOC_START(sam9rl)
.map_io = at91sam9rl_map_io,
.default_irq_priority = at91sam9rl_default_irq_priority,
.ioremap_registers = at91sam9rl_ioremap_registers,
.register_clocks = at91sam9rl_register_clocks,
.init = at91sam9rl_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index e5035380dcbc..3c729f0e2d3c 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -229,15 +229,17 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb0_clk),
CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
+ CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
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_ID("pioA", &pioAB_clk),
- CLKDEV_CON_ID("pioB", &pioAB_clk),
- CLKDEV_CON_ID("pioC", &pioCD_clk),
- CLKDEV_CON_ID("pioD", &pioCD_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),
+ CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
/* additional fake clock for macb_hclk */
CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
@@ -313,18 +315,11 @@ static void __init at91sam9x5_map_io(void)
at91_init_sram(0, AT91SAM9X5_SRAM_BASE, AT91SAM9X5_SRAM_SIZE);
}
-void __init at91sam9x5_initialize(void)
-{
- /* Register GPIO subsystem (using DT) */
- at91_gpio_init(NULL, 0);
-}
-
/* --------------------------------------------------------------------
* Interrupt initialization
* -------------------------------------------------------------------- */
-struct at91_init_soc __initdata at91sam9x5_soc = {
+AT91_SOC_START(sam9x5)
.map_io = at91sam9x5_map_io,
.register_clocks = at91sam9x5_register_clocks,
- .init = at91sam9x5_initialize,
-};
+AT91_SOC_END
diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
index e8f45c4e0ea8..3b6a94820fa0 100644
--- a/arch/arm/mach-at91/board-dt.c
+++ b/arch/arm/mach-at91/board-dt.c
@@ -30,8 +30,6 @@
static const struct of_device_id irq_of_match[] __initconst = {
{ .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
- { .compatible = "atmel,at91rm9200-gpio", .data = at91_gpio_of_irq_setup },
- { .compatible = "atmel,at91sam9x5-gpio", .data = at91_gpio_of_irq_setup },
{ /*sentinel*/ }
};
diff --git a/arch/arm/mach-at91/board-rm9200-dt.c b/arch/arm/mach-at91/board-rm9200-dt.c
new file mode 100644
index 000000000000..5f9ce3da3fde
--- /dev/null
+++ b/arch/arm/mach-at91/board-rm9200-dt.c
@@ -0,0 +1,57 @@
+/*
+ * Setup code for AT91RM9200 Evaluation Kits with Device Tree support
+ *
+ * Copyright (C) 2011 Atmel,
+ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>
+ * 2012 Joachim Eastwood <manabian@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include "at91_aic.h"
+#include "generic.h"
+
+
+static const struct of_device_id irq_of_match[] __initconst = {
+ { .compatible = "atmel,at91rm9200-aic", .data = at91_aic_of_init },
+ { /*sentinel*/ }
+};
+
+static void __init at91rm9200_dt_init_irq(void)
+{
+ of_irq_init(irq_of_match);
+}
+
+static void __init at91rm9200_dt_device_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *at91rm9200_dt_board_compat[] __initdata = {
+ "atmel,at91rm9200",
+ NULL
+};
+
+DT_MACHINE_START(at91rm9200_dt, "Atmel AT91RM9200 (Device Tree)")
+ .timer = &at91rm9200_timer,
+ .map_io = at91_map_io,
+ .handle_irq = at91_aic_handle_irq,
+ .init_early = at91rm9200_dt_initialize,
+ .init_irq = at91rm9200_dt_init_irq,
+ .init_machine = at91rm9200_dt_device_init,
+ .dt_compat = at91rm9200_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index b62f560e6c75..fc593d615e7d 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -20,6 +20,7 @@ extern void __init at91_init_sram(int bank, unsigned long base,
extern void __init at91rm9200_set_type(int type);
extern void __init at91_initialize(unsigned long main_clock);
extern void __init at91x40_initialize(unsigned long main_clock);
+extern void __init at91rm9200_dt_initialize(void);
extern void __init at91_dt_initialize(void);
/* Interrupts */
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index be42cf0e74bd..c5d7e1e9d757 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -23,8 +23,6 @@
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
#include <asm/mach/irq.h>
@@ -33,6 +31,8 @@
#include "generic.h"
+#define MAX_NB_GPIO_PER_BANK 32
+
struct at91_gpio_chip {
struct gpio_chip chip;
struct at91_gpio_chip *next; /* Bank sharing same clock */
@@ -46,6 +46,7 @@ struct at91_gpio_chip {
#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
@@ -55,26 +56,27 @@ static int at91_gpiolib_direction_input(struct gpio_chip *chip,
unsigned offset);
static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
-#define AT91_GPIO_CHIP(name, nr_gpio) \
+#define AT91_GPIO_CHIP(name) \
{ \
.chip = { \
.label = name, \
+ .request = at91_gpiolib_request, \
.direction_input = at91_gpiolib_direction_input, \
.direction_output = at91_gpiolib_direction_output, \
.get = at91_gpiolib_get, \
.set = at91_gpiolib_set, \
.dbg_show = at91_gpiolib_dbg_show, \
.to_irq = at91_gpiolib_to_irq, \
- .ngpio = nr_gpio, \
+ .ngpio = MAX_NB_GPIO_PER_BANK, \
}, \
}
static struct at91_gpio_chip gpio_chip[] = {
- AT91_GPIO_CHIP("pioA", 32),
- AT91_GPIO_CHIP("pioB", 32),
- AT91_GPIO_CHIP("pioC", 32),
- AT91_GPIO_CHIP("pioD", 32),
- AT91_GPIO_CHIP("pioE", 32),
+ AT91_GPIO_CHIP("pioA"),
+ AT91_GPIO_CHIP("pioB"),
+ AT91_GPIO_CHIP("pioC"),
+ AT91_GPIO_CHIP("pioD"),
+ AT91_GPIO_CHIP("pioE"),
};
static int gpio_banks;
@@ -89,7 +91,7 @@ static unsigned long at91_gpio_caps;
static inline void __iomem *pin_to_controller(unsigned pin)
{
- pin /= 32;
+ pin /= MAX_NB_GPIO_PER_BANK;
if (likely(pin < gpio_banks))
return gpio_chip[pin].regbase;
@@ -98,7 +100,7 @@ static inline void __iomem *pin_to_controller(unsigned pin)
static inline unsigned pin_to_mask(unsigned pin)
{
- return 1 << (pin % 32);
+ return 1 << (pin % MAX_NB_GPIO_PER_BANK);
}
@@ -713,80 +715,6 @@ postcore_initcall(at91_gpio_debugfs_init);
*/
static struct lock_class_key gpio_lock_class;
-#if defined(CONFIG_OF)
-static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- struct at91_gpio_chip *at91_gpio = h->host_data;
-
- irq_set_lockdep_class(virq, &gpio_lock_class);
-
- /*
- * Can use the "simple" and not "edge" handler since it's
- * shorter, and the AIC handles interrupts sanely.
- */
- irq_set_chip_and_handler(virq, &gpio_irqchip,
- handle_simple_irq);
- set_irq_flags(virq, IRQF_VALID);
- irq_set_chip_data(virq, at91_gpio);
-
- return 0;
-}
-
-static struct irq_domain_ops at91_gpio_ops = {
- .map = at91_gpio_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
-int __init at91_gpio_of_irq_setup(struct device_node *node,
- struct device_node *parent)
-{
- struct at91_gpio_chip *prev = NULL;
- int alias_idx = of_alias_get_id(node, "gpio");
- struct at91_gpio_chip *at91_gpio = &gpio_chip[alias_idx];
-
- /* Setup proper .irq_set_type function */
- if (has_pio3())
- gpio_irqchip.irq_set_type = alt_gpio_irq_type;
- else
- gpio_irqchip.irq_set_type = gpio_irq_type;
-
- /* Disable irqs of this PIO controller */
- __raw_writel(~0, at91_gpio->regbase + PIO_IDR);
-
- /* Setup irq domain */
- at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
- &at91_gpio_ops, at91_gpio);
- if (!at91_gpio->domain)
- panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
- at91_gpio->pioc_idx);
-
- /* Setup chained handler */
- if (at91_gpio->pioc_idx)
- prev = &gpio_chip[at91_gpio->pioc_idx - 1];
-
- /* The toplevel handler handles one bank of GPIOs, except
- * on some SoC it can handles up to three...
- * We only set up the handler for the first of the list.
- */
- if (prev && prev->next == at91_gpio)
- return 0;
-
- at91_gpio->pioc_virq = irq_create_mapping(irq_find_host(parent),
- at91_gpio->pioc_hwirq);
- irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
- irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
-
- return 0;
-}
-#else
-int __init at91_gpio_of_irq_setup(struct device_node *node,
- struct device_node *parent)
-{
- return -EINVAL;
-}
-#endif
-
/*
* irqdomain initialization: pile up irqdomains on top of AIC range
*/
@@ -862,6 +790,16 @@ void __init at91_gpio_irq_setup(void)
}
/* gpiolib support */
+static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ __raw_writel(mask, pio + PIO_PER);
+ return 0;
+}
+
static int at91_gpiolib_direction_input(struct gpio_chip *chip,
unsigned offset)
{
@@ -975,81 +913,11 @@ err:
return -EINVAL;
}
-#ifdef CONFIG_OF_GPIO
-static void __init of_at91_gpio_init_one(struct device_node *np)
-{
- int alias_idx;
- struct at91_gpio_chip *at91_gpio;
-
- if (!np)
- return;
-
- alias_idx = of_alias_get_id(np, "gpio");
- if (alias_idx >= MAX_GPIO_BANKS) {
- pr_err("at91_gpio, failed alias idx(%d) > MAX_GPIO_BANKS(%d), ignoring.\n",
- alias_idx, MAX_GPIO_BANKS);
- return;
- }
-
- at91_gpio = &gpio_chip[alias_idx];
- at91_gpio->chip.base = alias_idx * at91_gpio->chip.ngpio;
-
- at91_gpio->regbase = of_iomap(np, 0);
- if (!at91_gpio->regbase) {
- pr_err("at91_gpio.%d, failed to map registers, ignoring.\n",
- alias_idx);
- return;
- }
-
- /* Get the interrupts property */
- if (of_property_read_u32(np, "interrupts", &at91_gpio->pioc_hwirq)) {
- pr_err("at91_gpio.%d, failed to get interrupts property, ignoring.\n",
- alias_idx);
- goto ioremap_err;
- }
-
- /* Get capabilities from compatibility property */
- if (of_device_is_compatible(np, "atmel,at91sam9x5-gpio"))
- at91_gpio_caps |= AT91_GPIO_CAP_PIO3;
-
- /* Setup clock */
- if (at91_gpio_setup_clk(alias_idx))
- goto ioremap_err;
-
- at91_gpio->chip.of_node = np;
- gpio_banks = max(gpio_banks, alias_idx + 1);
- at91_gpio->pioc_idx = alias_idx;
- return;
-
-ioremap_err:
- iounmap(at91_gpio->regbase);
-}
-
-static int __init of_at91_gpio_init(void)
-{
- struct device_node *np = NULL;
-
- /*
- * This isn't ideal, but it gets things hooked up until this
- * driver is converted into a platform_device
- */
- for_each_compatible_node(np, NULL, "atmel,at91rm9200-gpio")
- of_at91_gpio_init_one(np);
-
- return gpio_banks > 0 ? 0 : -EINVAL;
-}
-#else
-static int __init of_at91_gpio_init(void)
-{
- return -EINVAL;
-}
-#endif
-
static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
{
struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
- at91_gpio->chip.base = idx * at91_gpio->chip.ngpio;
+ at91_gpio->chip.base = idx * MAX_NB_GPIO_PER_BANK;
at91_gpio->pioc_hwirq = pioc_hwirq;
at91_gpio->pioc_idx = idx;
@@ -1079,11 +947,11 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
BUG_ON(nr_banks > MAX_GPIO_BANKS);
- if (of_at91_gpio_init() < 0) {
- /* No GPIO controller found in device tree */
- for (i = 0; i < nr_banks; i++)
- at91_gpio_init_one(i, data[i].regbase, data[i].id);
- }
+ if (of_have_populated_dt())
+ return;
+
+ for (i = 0; i < nr_banks; i++)
+ at91_gpio_init_one(i, data[i].regbase, data[i].id);
for (i = 0; i < gpio_banks; i++) {
at91_gpio = &gpio_chip[i];
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index c55a4364ffb4..a0d92a960f46 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -70,16 +70,6 @@ struct at91_cf_data {
extern void __init at91_add_device_cf(struct at91_cf_data *data);
/* MMC / SD */
- /* at91_mci platform config */
-struct at91_mmc_data {
- int det_pin; /* card detect IRQ */
- unsigned slot_b:1; /* uses Slot B */
- unsigned wire4:1; /* (SD) supports DAT0..DAT3 */
- int wp_pin; /* (SD) writeprotect detect */
- int vcc_pin; /* power switching (high == on) */
-};
-extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
-
/* atmel-mci platform config */
extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 0b32c81730a5..19cdd0b5b391 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/pm.h>
#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
#include <asm/system_misc.h>
#include <asm/mach/map.h>
@@ -338,6 +339,7 @@ static void at91_dt_rstc(void)
}
static struct of_device_id ramc_ids[] = {
+ { .compatible = "atmel,at91rm9200-sdramc" },
{ .compatible = "atmel,at91sam9260-sdramc" },
{ .compatible = "atmel,at91sam9g45-ddramc" },
{ /*sentinel*/ }
@@ -436,6 +438,19 @@ end:
of_node_put(np);
}
+void __init at91rm9200_dt_initialize(void)
+{
+ at91_dt_ramc();
+
+ /* Init clock subsystem */
+ at91_dt_clock_init();
+
+ /* Register the processor-specific clocks */
+ at91_boot_soc.register_clocks();
+
+ at91_boot_soc.init();
+}
+
void __init at91_dt_initialize(void)
{
at91_dt_rstc();
@@ -448,7 +463,8 @@ void __init at91_dt_initialize(void)
/* Register the processor-specific clocks */
at91_boot_soc.register_clocks();
- at91_boot_soc.init();
+ if (at91_boot_soc.init)
+ at91_boot_soc.init();
}
#endif
@@ -463,4 +479,6 @@ void __init at91_initialize(unsigned long main_clock)
at91_boot_soc.register_clocks();
at91_boot_soc.init();
+
+ pinctrl_provide_dummies();
}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index a9cfeb153719..9c6d3d4f9a23 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -5,6 +5,7 @@
*/
struct at91_init_soc {
+ int builtin;
unsigned int *default_irq_priority;
void (*map_io)(void);
void (*ioremap_registers)(void);
@@ -22,9 +23,18 @@ extern struct at91_init_soc at91sam9rl_soc;
extern struct at91_init_soc at91sam9x5_soc;
extern struct at91_init_soc at91sam9n12_soc;
+#define AT91_SOC_START(_name) \
+struct at91_init_soc __initdata at91##_name##_soc \
+ __used \
+ = { \
+ .builtin = 1, \
+
+#define AT91_SOC_END \
+};
+
static inline int at91_soc_is_enabled(void)
{
- return at91_boot_soc.init != NULL;
+ return at91_boot_soc.builtin;
}
#if !defined(CONFIG_SOC_AT91RM9200)
diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c
index cd0c8b1e1ecf..14e9947bad6e 100644
--- a/arch/arm/mach-davinci/dm644x.c
+++ b/arch/arm/mach-davinci/dm644x.c
@@ -713,8 +713,7 @@ static int dm644x_venc_setup_clock(enum vpbe_enc_timings_type type,
break;
case VPBE_ENC_CUSTOM_TIMINGS:
if (pclock <= 27000000) {
- v |= DM644X_VPSS_MUXSEL_PLL2_MODE |
- DM644X_VPSS_DACCLKEN;
+ v |= DM644X_VPSS_DACCLKEN;
writel(v, DAVINCI_SYSMOD_VIRT(SYSMOD_VPSS_CLKCTL));
} else {
/*
diff --git a/arch/arm/mach-dove/include/mach/pm.h b/arch/arm/mach-dove/include/mach/pm.h
index 7bcd0dfce4b1..b47f75038686 100644
--- a/arch/arm/mach-dove/include/mach/pm.h
+++ b/arch/arm/mach-dove/include/mach/pm.h
@@ -63,7 +63,7 @@ static inline int pmu_to_irq(int pin)
static inline int irq_to_pmu(int irq)
{
- if (IRQ_DOVE_PMU_START < irq && irq < NR_IRQS)
+ if (IRQ_DOVE_PMU_START <= irq && irq < NR_IRQS)
return irq - IRQ_DOVE_PMU_START;
return -EINVAL;
diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c
index 087711524e8a..bc4344aa1009 100644
--- a/arch/arm/mach-dove/irq.c
+++ b/arch/arm/mach-dove/irq.c
@@ -46,8 +46,20 @@ static void pmu_irq_ack(struct irq_data *d)
int pin = irq_to_pmu(d->irq);
u32 u;
+ /*
+ * The PMU mask register is not RW0C: it is RW. This means that
+ * the bits take whatever value is written to them; if you write
+ * a '1', you will set the interrupt.
+ *
+ * Unfortunately this means there is NO race free way to clear
+ * these interrupts.
+ *
+ * So, let's structure the code so that the window is as small as
+ * possible.
+ */
u = ~(1 << (pin & 31));
- writel(u, PMU_INTERRUPT_CAUSE);
+ u &= readl_relaxed(PMU_INTERRUPT_CAUSE);
+ writel_relaxed(u, PMU_INTERRUPT_CAUSE);
}
static struct irq_chip pmu_irq_chip = {
diff --git a/arch/arm/mach-exynos/dma.c b/arch/arm/mach-exynos/dma.c
index 21d568b3b149..87e07d6fc615 100644
--- a/arch/arm/mach-exynos/dma.c
+++ b/arch/arm/mach-exynos/dma.c
@@ -275,6 +275,9 @@ static int __init exynos_dma_init(void)
exynos_pdma1_pdata.nr_valid_peri =
ARRAY_SIZE(exynos4210_pdma1_peri);
exynos_pdma1_pdata.peri_id = exynos4210_pdma1_peri;
+
+ if (samsung_rev() == EXYNOS4210_REV_0)
+ exynos_mdma1_device.res.start = EXYNOS4_PA_S_MDMA1;
} else if (soc_is_exynos4212() || soc_is_exynos4412()) {
exynos_pdma0_pdata.nr_valid_peri =
ARRAY_SIZE(exynos4212_pdma0_peri);
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 8480849affb9..ed4da4544cd2 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -90,6 +90,7 @@
#define EXYNOS4_PA_MDMA0 0x10810000
#define EXYNOS4_PA_MDMA1 0x12850000
+#define EXYNOS4_PA_S_MDMA1 0x12840000
#define EXYNOS4_PA_PDMA0 0x12680000
#define EXYNOS4_PA_PDMA1 0x12690000
#define EXYNOS5_PA_MDMA0 0x10800000
diff --git a/arch/arm/mach-highbank/system.c b/arch/arm/mach-highbank/system.c
index 82c27230d4a9..86e37cd9376c 100644
--- a/arch/arm/mach-highbank/system.c
+++ b/arch/arm/mach-highbank/system.c
@@ -28,6 +28,7 @@ void highbank_restart(char mode, const char *cmd)
hignbank_set_pwr_soft_reset();
scu_power_mode(scu_base_addr, SCU_PM_POWEROFF);
- cpu_do_idle();
+ while (1)
+ cpu_do_idle();
}
diff --git a/arch/arm/mach-imx/clk-gate2.c b/arch/arm/mach-imx/clk-gate2.c
index 3c1b8ff9a0a6..cc49c7ae186e 100644
--- a/arch/arm/mach-imx/clk-gate2.c
+++ b/arch/arm/mach-imx/clk-gate2.c
@@ -112,7 +112,7 @@ struct clk *clk_register_gate2(struct device *dev, const char *name,
clk = clk_register(dev, &gate->hw);
if (IS_ERR(clk))
- kfree(clk);
+ kfree(gate);
return clk;
}
diff --git a/arch/arm/mach-imx/ehci-imx25.c b/arch/arm/mach-imx/ehci-imx25.c
index 412c583a24b0..576af7446952 100644
--- a/arch/arm/mach-imx/ehci-imx25.c
+++ b/arch/arm/mach-imx/ehci-imx25.c
@@ -30,7 +30,7 @@
#define MX25_H1_SIC_SHIFT 21
#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT)
#define MX25_H1_PP_BIT (1 << 18)
-#define MX25_H1_PM_BIT (1 << 8)
+#define MX25_H1_PM_BIT (1 << 16)
#define MX25_H1_IPPUE_UP_BIT (1 << 7)
#define MX25_H1_IPPUE_DOWN_BIT (1 << 6)
#define MX25_H1_TLL_BIT (1 << 5)
diff --git a/arch/arm/mach-imx/ehci-imx35.c b/arch/arm/mach-imx/ehci-imx35.c
index 779e16eb65cb..293397852e4e 100644
--- a/arch/arm/mach-imx/ehci-imx35.c
+++ b/arch/arm/mach-imx/ehci-imx35.c
@@ -30,7 +30,7 @@
#define MX35_H1_SIC_SHIFT 21
#define MX35_H1_SIC_MASK (0x3 << MX35_H1_SIC_SHIFT)
#define MX35_H1_PP_BIT (1 << 18)
-#define MX35_H1_PM_BIT (1 << 8)
+#define MX35_H1_PM_BIT (1 << 16)
#define MX35_H1_IPPUE_UP_BIT (1 << 7)
#define MX35_H1_IPPUE_DOWN_BIT (1 << 6)
#define MX35_H1_TLL_BIT (1 << 5)
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c
index e428f3ab15c7..b3d86d7081a0 100644
--- a/arch/arm/mach-integrator/impd1.c
+++ b/arch/arm/mach-integrator/impd1.c
@@ -21,10 +21,9 @@
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/io.h>
+#include <linux/platform_data/clk-integrator.h>
#include <linux/slab.h>
-#include <linux/clkdev.h>
-#include <asm/hardware/icst.h>
#include <mach/lm.h>
#include <mach/impd1.h>
#include <asm/sizes.h>
@@ -36,45 +35,6 @@ MODULE_PARM_DESC(lmid, "logic module stack position");
struct impd1_module {
void __iomem *base;
- struct clk vcos[2];
- struct clk_lookup *clks[3];
-};
-
-static const struct icst_params impd1_vco_params = {
- .ref = 24000000, /* 24 MHz */
- .vco_max = ICST525_VCO_MAX_3V,
- .vco_min = ICST525_VCO_MIN,
- .vd_min = 12,
- .vd_max = 519,
- .rd_min = 3,
- .rd_max = 120,
- .s2div = icst525_s2div,
- .idx2s = icst525_idx2s,
-};
-
-static void impd1_setvco(struct clk *clk, struct icst_vco vco)
-{
- struct impd1_module *impd1 = clk->data;
- u32 val = vco.v | (vco.r << 9) | (vco.s << 16);
-
- writel(0xa05f, impd1->base + IMPD1_LOCK);
- writel(val, clk->vcoreg);
- writel(0, impd1->base + IMPD1_LOCK);
-
-#ifdef DEBUG
- vco.v = val & 0x1ff;
- vco.r = (val >> 9) & 0x7f;
- vco.s = (val >> 16) & 7;
-
- pr_debug("IM-PD1: VCO%d clock is %ld Hz\n",
- vconr, icst525_hz(&impd1_vco_params, vco));
-#endif
-}
-
-static const struct clk_ops impd1_clk_ops = {
- .round = icst_clk_round,
- .set = icst_clk_set,
- .setvco = impd1_setvco,
};
void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
@@ -344,10 +304,6 @@ static struct impd1_device impd1_devs[] = {
}
};
-static struct clk fixed_14745600 = {
- .rate = 14745600,
-};
-
static int impd1_probe(struct lm_device *dev)
{
struct impd1_module *impd1;
@@ -376,23 +332,7 @@ static int impd1_probe(struct lm_device *dev)
printk("IM-PD1 found at 0x%08lx\n",
(unsigned long)dev->resource.start);
- for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) {
- impd1->vcos[i].ops = &impd1_clk_ops,
- impd1->vcos[i].owner = THIS_MODULE,
- impd1->vcos[i].params = &impd1_vco_params,
- impd1->vcos[i].data = impd1;
- }
- impd1->vcos[0].vcoreg = impd1->base + IMPD1_OSC1;
- impd1->vcos[1].vcoreg = impd1->base + IMPD1_OSC2;
-
- impd1->clks[0] = clkdev_alloc(&impd1->vcos[0], NULL, "lm%x:01000",
- dev->id);
- impd1->clks[1] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00100",
- dev->id);
- impd1->clks[2] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00200",
- dev->id);
- for (i = 0; i < ARRAY_SIZE(impd1->clks); i++)
- clkdev_add(impd1->clks[i]);
+ integrator_impd1_clk_init(impd1->base, dev->id);
for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
struct impd1_device *idev = impd1_devs + i;
@@ -431,12 +371,9 @@ static int impd1_remove_one(struct device *dev, void *data)
static void impd1_remove(struct lm_device *dev)
{
struct impd1_module *impd1 = lm_get_drvdata(dev);
- int i;
device_for_each_child(&dev->dev, NULL, impd1_remove_one);
-
- for (i = 0; i < ARRAY_SIZE(impd1->clks); i++)
- clkdev_drop(impd1->clks[i]);
+ integrator_impd1_clk_exit(dev->id);
lm_set_drvdata(dev, NULL);
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 1694f01ce2b6..6d6bde3e15fa 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -410,6 +410,7 @@ void __init ixp4xx_pci_preinit(void)
* Enable the IO window to be way up high, at 0xfffffc00
*/
local_write_config(PCI_BASE_ADDRESS_5, 4, 0xfffffc01);
+ local_write_config(0x40, 4, 0x000080FF); /* No TRDY time limit */
} else {
printk("PCI: IXP4xx is target - No bus scan performed\n");
}
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index fdf91a160884..8c0c0e2d0727 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -67,15 +67,12 @@ static struct map_desc ixp4xx_io_desc[] __initdata = {
.pfn = __phys_to_pfn(IXP4XX_PCI_CFG_BASE_PHYS),
.length = IXP4XX_PCI_CFG_REGION_SIZE,
.type = MT_DEVICE
- },
-#ifdef CONFIG_DEBUG_LL
- { /* Debug UART mapping */
- .virtual = (unsigned long)IXP4XX_DEBUG_UART_BASE_VIRT,
- .pfn = __phys_to_pfn(IXP4XX_DEBUG_UART_BASE_PHYS),
- .length = IXP4XX_DEBUG_UART_REGION_SIZE,
+ }, { /* Queue Manager */
+ .virtual = (unsigned long)IXP4XX_QMGR_BASE_VIRT,
+ .pfn = __phys_to_pfn(IXP4XX_QMGR_BASE_PHYS),
+ .length = IXP4XX_QMGR_REGION_SIZE,
.type = MT_DEVICE
- }
-#endif
+ },
};
void __init ixp4xx_map_io(void)
diff --git a/arch/arm/mach-ixp4xx/goramo_mlr.c b/arch/arm/mach-ixp4xx/goramo_mlr.c
index b800a031207c..53b8348dfcc2 100644
--- a/arch/arm/mach-ixp4xx/goramo_mlr.c
+++ b/arch/arm/mach-ixp4xx/goramo_mlr.c
@@ -15,6 +15,7 @@
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
#include <asm/mach/pci.h>
+#include <asm/system_info.h>
#define SLOT_ETHA 0x0B /* IDSEL = AD21 */
#define SLOT_ETHB 0x0C /* IDSEL = AD20 */
@@ -329,7 +330,7 @@ static struct platform_device device_hss_tab[] = {
};
-static struct platform_device *device_tab[6] __initdata = {
+static struct platform_device *device_tab[7] __initdata = {
&device_flash, /* index 0 */
};
diff --git a/arch/arm/mach-ixp4xx/include/mach/debug-macro.S b/arch/arm/mach-ixp4xx/include/mach/debug-macro.S
index 8c9f8d564492..ff686cbc5df4 100644
--- a/arch/arm/mach-ixp4xx/include/mach/debug-macro.S
+++ b/arch/arm/mach-ixp4xx/include/mach/debug-macro.S
@@ -17,8 +17,8 @@
#else
mov \rp, #0
#endif
- orr \rv, \rp, #0xff000000 @ virtual
- orr \rv, \rv, #0x00b00000
+ orr \rv, \rp, #0xfe000000 @ virtual
+ orr \rv, \rv, #0x00f00000
orr \rp, \rp, #0xc8000000 @ physical
.endm
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
index eb68b61ce975..c5bae9c035d5 100644
--- a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h
@@ -30,51 +30,43 @@
*
* 0x50000000 0x10000000 ioremap'd EXP BUS
*
- * 0x6000000 0x00004000 ioremap'd QMgr
+ * 0xC8000000 0x00013000 0xFEF00000 On-Chip Peripherals
*
- * 0xC0000000 0x00001000 0xffbff000 PCI CFG
+ * 0xC0000000 0x00001000 0xFEF13000 PCI CFG
*
- * 0xC4000000 0x00001000 0xffbfe000 EXP CFG
+ * 0xC4000000 0x00001000 0xFEF14000 EXP CFG
*
- * 0xC8000000 0x00013000 0xffbeb000 On-Chip Peripherals
+ * 0x60000000 0x00004000 0xFEF15000 QMgr
*/
/*
* Queue Manager
*/
-#define IXP4XX_QMGR_BASE_PHYS (0x60000000)
-#define IXP4XX_QMGR_REGION_SIZE (0x00004000)
+#define IXP4XX_QMGR_BASE_PHYS 0x60000000
+#define IXP4XX_QMGR_BASE_VIRT IOMEM(0xFEF15000)
+#define IXP4XX_QMGR_REGION_SIZE 0x00004000
/*
- * Expansion BUS Configuration registers
+ * Peripheral space, including debug UART. Must be section-aligned so that
+ * it can be used with the low-level debug code.
*/
-#define IXP4XX_EXP_CFG_BASE_PHYS (0xC4000000)
-#define IXP4XX_EXP_CFG_BASE_VIRT IOMEM(0xFFBFE000)
-#define IXP4XX_EXP_CFG_REGION_SIZE (0x00001000)
+#define IXP4XX_PERIPHERAL_BASE_PHYS 0xC8000000
+#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFEF00000)
+#define IXP4XX_PERIPHERAL_REGION_SIZE 0x00013000
/*
* PCI Config registers
*/
-#define IXP4XX_PCI_CFG_BASE_PHYS (0xC0000000)
-#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFFBFF000)
-#define IXP4XX_PCI_CFG_REGION_SIZE (0x00001000)
-
-/*
- * Peripheral space
- */
-#define IXP4XX_PERIPHERAL_BASE_PHYS (0xC8000000)
-#define IXP4XX_PERIPHERAL_BASE_VIRT IOMEM(0xFFBEB000)
-#define IXP4XX_PERIPHERAL_REGION_SIZE (0x00013000)
+#define IXP4XX_PCI_CFG_BASE_PHYS 0xC0000000
+#define IXP4XX_PCI_CFG_BASE_VIRT IOMEM(0xFEF13000)
+#define IXP4XX_PCI_CFG_REGION_SIZE 0x00001000
/*
- * Debug UART
- *
- * This is basically a remap of UART1 into a region that is section
- * aligned so that it * can be used with the low-level debug code.
+ * Expansion BUS Configuration registers
*/
-#define IXP4XX_DEBUG_UART_BASE_PHYS (0xC8000000)
-#define IXP4XX_DEBUG_UART_BASE_VIRT IOMEM(0xffb00000)
-#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
+#define IXP4XX_EXP_CFG_BASE_PHYS 0xC4000000
+#define IXP4XX_EXP_CFG_BASE_VIRT 0xFEF14000
+#define IXP4XX_EXP_CFG_REGION_SIZE 0x00001000
#define IXP4XX_EXP_CS0_OFFSET 0x00
#define IXP4XX_EXP_CS1_OFFSET 0x04
diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
index 9e7cad2d54cb..4de8da536dbb 100644
--- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h
+++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h
@@ -86,7 +86,7 @@ void qmgr_release_queue(unsigned int queue);
static inline void qmgr_put_entry(unsigned int queue, u32 val)
{
- extern struct qmgr_regs __iomem *qmgr_regs;
+ struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
#if DEBUG_QMGR
BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
@@ -99,7 +99,7 @@ static inline void qmgr_put_entry(unsigned int queue, u32 val)
static inline u32 qmgr_get_entry(unsigned int queue)
{
u32 val;
- extern struct qmgr_regs __iomem *qmgr_regs;
+ const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
val = __raw_readl(&qmgr_regs->acc[queue][0]);
#if DEBUG_QMGR
BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */
@@ -112,14 +112,14 @@ static inline u32 qmgr_get_entry(unsigned int queue)
static inline int __qmgr_get_stat1(unsigned int queue)
{
- extern struct qmgr_regs __iomem *qmgr_regs;
+ const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
return (__raw_readl(&qmgr_regs->stat1[queue >> 3])
>> ((queue & 7) << 2)) & 0xF;
}
static inline int __qmgr_get_stat2(unsigned int queue)
{
- extern struct qmgr_regs __iomem *qmgr_regs;
+ const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
BUG_ON(queue >= HALF_QUEUES);
return (__raw_readl(&qmgr_regs->stat2[queue >> 4])
>> ((queue & 0xF) << 1)) & 0x3;
@@ -145,7 +145,7 @@ static inline int qmgr_stat_empty(unsigned int queue)
*/
static inline int qmgr_stat_below_low_watermark(unsigned int queue)
{
- extern struct qmgr_regs __iomem *qmgr_regs;
+ const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
if (queue >= HALF_QUEUES)
return (__raw_readl(&qmgr_regs->statne_h) >>
(queue - HALF_QUEUES)) & 0x01;
@@ -172,7 +172,7 @@ static inline int qmgr_stat_above_high_watermark(unsigned int queue)
*/
static inline int qmgr_stat_full(unsigned int queue)
{
- extern struct qmgr_regs __iomem *qmgr_regs;
+ const struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
if (queue >= HALF_QUEUES)
return (__raw_readl(&qmgr_regs->statf_h) >>
(queue - HALF_QUEUES)) & 0x01;
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
index a17ed79207a4..d4eb09a62863 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
@@ -116,7 +116,11 @@
/* NPE mailbox_status value for reset */
#define RESET_MBOX_STAT 0x0000F0F0
-const char *npe_names[] = { "NPE-A", "NPE-B", "NPE-C" };
+#define NPE_A_FIRMWARE "NPE-A"
+#define NPE_B_FIRMWARE "NPE-B"
+#define NPE_C_FIRMWARE "NPE-C"
+
+const char *npe_names[] = { NPE_A_FIRMWARE, NPE_B_FIRMWARE, NPE_C_FIRMWARE };
#define print_npe(pri, npe, fmt, ...) \
printk(pri "%s: " fmt, npe_name(npe), ## __VA_ARGS__)
@@ -724,6 +728,9 @@ module_exit(npe_cleanup_module);
MODULE_AUTHOR("Krzysztof Halasa");
MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE(NPE_A_FIRMWARE);
+MODULE_FIRMWARE(NPE_B_FIRMWARE);
+MODULE_FIRMWARE(NPE_C_FIRMWARE);
EXPORT_SYMBOL(npe_names);
EXPORT_SYMBOL(npe_running);
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
index 852f7c9f87d0..9d1b6b7c394c 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
@@ -14,7 +14,7 @@
#include <linux/module.h>
#include <mach/qmgr.h>
-struct qmgr_regs __iomem *qmgr_regs;
+static struct qmgr_regs __iomem *qmgr_regs = IXP4XX_QMGR_BASE_VIRT;
static struct resource *mem_res;
static spinlock_t qmgr_lock;
static u32 used_sram_bitmap[4]; /* 128 16-dword pages */
@@ -293,12 +293,6 @@ static int qmgr_init(void)
if (mem_res == NULL)
return -EBUSY;
- qmgr_regs = ioremap(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
- if (qmgr_regs == NULL) {
- err = -ENOMEM;
- goto error_map;
- }
-
/* reset qmgr registers */
for (i = 0; i < 4; i++) {
__raw_writel(0x33333333, &qmgr_regs->stat1[i]);
@@ -347,8 +341,6 @@ static int qmgr_init(void)
error_irq2:
free_irq(IRQ_IXP4XX_QM1, NULL);
error_irq:
- iounmap(qmgr_regs);
-error_map:
release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
return err;
}
@@ -359,7 +351,6 @@ static void qmgr_remove(void)
free_irq(IRQ_IXP4XX_QM2, NULL);
synchronize_irq(IRQ_IXP4XX_QM1);
synchronize_irq(IRQ_IXP4XX_QM2);
- iounmap(qmgr_regs);
release_mem_region(IXP4XX_QMGR_BASE_PHYS, IXP4XX_QMGR_REGION_SIZE);
}
@@ -369,7 +360,6 @@ module_exit(qmgr_remove);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Krzysztof Halasa");
-EXPORT_SYMBOL(qmgr_regs);
EXPORT_SYMBOL(qmgr_set_irq);
EXPORT_SYMBOL(qmgr_enable_irq);
EXPORT_SYMBOL(qmgr_disable_irq);
diff --git a/arch/arm/mach-kirkwood/pcie.c b/arch/arm/mach-kirkwood/pcie.c
index ec544918b12c..74fc5a074fc4 100644
--- a/arch/arm/mach-kirkwood/pcie.c
+++ b/arch/arm/mach-kirkwood/pcie.c
@@ -207,14 +207,19 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
return 1;
}
+/*
+ * The root complex has a hardwired class of PCI_CLASS_MEMORY_OTHER, when it
+ * is operating as a root complex this needs to be switched to
+ * PCI_CLASS_BRIDGE_HOST or Linux will errantly try to process the BAR's on
+ * the device. Decoding setup is handled by the orion code.
+ */
static void __devinit rc_pci_fixup(struct pci_dev *dev)
{
- /*
- * Prevent enumeration of root complex.
- */
if (dev->bus->parent == NULL && dev->devfn == 0) {
int i;
+ dev->class &= 0xff;
+ dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
dev->resource[i].start = 0;
dev->resource[i].end = 0;
diff --git a/arch/arm/mach-nomadik/board-nhk8815.c b/arch/arm/mach-nomadik/board-nhk8815.c
index bfa1eab91f41..22ef8a1abe08 100644
--- a/arch/arm/mach-nomadik/board-nhk8815.c
+++ b/arch/arm/mach-nomadik/board-nhk8815.c
@@ -24,6 +24,7 @@
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/hardware/vic.h>
#include <asm/sizes.h>
#include <asm/mach-types.h>
@@ -32,9 +33,7 @@
#include <asm/mach/flash.h>
#include <asm/mach/time.h>
-#include <plat/gpio-nomadik.h>
#include <plat/mtu.h>
-#include <plat/pincfg.h>
#include <linux/platform_data/mtd-nomadik-nand.h>
#include <mach/fsmc.h>
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index b617eaed0ce5..1273931303fb 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -26,8 +26,8 @@
#include <linux/irq.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/clk-nomadik.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
-#include <plat/gpio-nomadik.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
#include <asm/mach/map.h>
diff --git a/arch/arm/mach-nomadik/i2c-8815nhk.c b/arch/arm/mach-nomadik/i2c-8815nhk.c
index 6d14454d4609..0c2f6628299a 100644
--- a/arch/arm/mach-nomadik/i2c-8815nhk.c
+++ b/arch/arm/mach-nomadik/i2c-8815nhk.c
@@ -4,8 +4,7 @@
#include <linux/i2c-algo-bit.h>
#include <linux/i2c-gpio.h>
#include <linux/platform_device.h>
-#include <plat/gpio-nomadik.h>
-#include <plat/pincfg.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
/*
* There are two busses in the 8815NHK.
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 48d5e41dfbfa..378590694447 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -580,6 +580,11 @@ static void __init igep_wlan_bt_init(void)
} else
return;
+ /* Make sure that the GPIO pins are muxed correctly */
+ omap_mux_init_gpio(igep_wlan_bt_gpios[0].gpio, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(igep_wlan_bt_gpios[1].gpio, OMAP_PIN_OUTPUT);
+ omap_mux_init_gpio(igep_wlan_bt_gpios[2].gpio, OMAP_PIN_OUTPUT);
+
err = gpio_request_array(igep_wlan_bt_gpios,
ARRAY_SIZE(igep_wlan_bt_gpios));
if (err) {
diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c
index b56d06b48782..95192a062d5d 100644
--- a/arch/arm/mach-omap2/clockdomains44xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains44xx_data.c
@@ -359,7 +359,7 @@ static struct clockdomain iss_44xx_clkdm = {
.clkdm_offs = OMAP4430_CM2_CAM_CAM_CDOFFS,
.wkdep_srcs = iss_wkup_sleep_deps,
.sleepdep_srcs = iss_wkup_sleep_deps,
- .flags = CLKDM_CAN_HWSUP_SWSUP,
+ .flags = CLKDM_CAN_SWSUP,
};
static struct clockdomain l3_dss_44xx_clkdm = {
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
index 48daac2581b4..84551f205e46 100644
--- a/arch/arm/mach-omap2/common-board-devices.c
+++ b/arch/arm/mach-omap2/common-board-devices.c
@@ -64,30 +64,36 @@ void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
struct spi_board_info *spi_bi = &ads7846_spi_board_info;
int err;
- err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown");
- if (err) {
- pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err);
- return;
- }
+ /*
+ * If a board defines get_pendown_state() function, request the pendown
+ * GPIO and set the GPIO debounce time.
+ * If a board does not define the get_pendown_state() function, then
+ * the ads7846 driver will setup the pendown GPIO itself.
+ */
+ if (board_pdata && board_pdata->get_pendown_state) {
+ err = gpio_request_one(gpio_pendown, GPIOF_IN, "TSPenDown");
+ if (err) {
+ pr_err("Couldn't obtain gpio for TSPenDown: %d\n", err);
+ return;
+ }
- if (gpio_debounce)
- gpio_set_debounce(gpio_pendown, gpio_debounce);
+ if (gpio_debounce)
+ gpio_set_debounce(gpio_pendown, gpio_debounce);
+
+ gpio_export(gpio_pendown, 0);
+ }
spi_bi->bus_num = bus_num;
spi_bi->irq = gpio_to_irq(gpio_pendown);
+ ads7846_config.gpio_pendown = gpio_pendown;
+
if (board_pdata) {
board_pdata->gpio_pendown = gpio_pendown;
+ board_pdata->gpio_pendown_debounce = gpio_debounce;
spi_bi->platform_data = board_pdata;
- if (board_pdata->get_pendown_state)
- gpio_export(gpio_pendown, 0);
- } else {
- ads7846_config.gpio_pendown = gpio_pendown;
}
- if (!board_pdata || (board_pdata && !board_pdata->get_pendown_state))
- gpio_free(gpio_pendown);
-
spi_register_board_info(&ads7846_spi_board_info, 1);
}
#else
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index cba60e05e32e..c72b5a727720 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -19,6 +19,7 @@
#include <linux/of.h>
#include <linux/pinctrl/machine.h>
#include <linux/platform_data/omap4-keypad.h>
+#include <linux/platform_data/omap_ocp2scp.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
@@ -613,6 +614,83 @@ static void omap_init_vout(void)
static inline void omap_init_vout(void) {}
#endif
+#if defined(CONFIG_OMAP_OCP2SCP) || defined(CONFIG_OMAP_OCP2SCP_MODULE)
+static int count_ocp2scp_devices(struct omap_ocp2scp_dev *ocp2scp_dev)
+{
+ int cnt = 0;
+
+ while (ocp2scp_dev->drv_name != NULL) {
+ cnt++;
+ ocp2scp_dev++;
+ }
+
+ return cnt;
+}
+
+static void omap_init_ocp2scp(void)
+{
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ int bus_id = -1, dev_cnt = 0, i;
+ struct omap_ocp2scp_dev *ocp2scp_dev;
+ const char *oh_name, *name;
+ struct omap_ocp2scp_platform_data *pdata;
+
+ if (!cpu_is_omap44xx())
+ return;
+
+ oh_name = "ocp2scp_usb_phy";
+ name = "omap-ocp2scp";
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("%s: could not find omap_hwmod for %s\n", __func__,
+ oh_name);
+ return;
+ }
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ pr_err("%s: No memory for ocp2scp pdata\n", __func__);
+ return;
+ }
+
+ ocp2scp_dev = oh->dev_attr;
+ dev_cnt = count_ocp2scp_devices(ocp2scp_dev);
+
+ if (!dev_cnt) {
+ pr_err("%s: No devices connected to ocp2scp\n", __func__);
+ kfree(pdata);
+ return;
+ }
+
+ pdata->devices = kzalloc(sizeof(struct omap_ocp2scp_dev *)
+ * dev_cnt, GFP_KERNEL);
+ if (!pdata->devices) {
+ pr_err("%s: No memory for ocp2scp pdata devices\n", __func__);
+ kfree(pdata);
+ return;
+ }
+
+ for (i = 0; i < dev_cnt; i++, ocp2scp_dev++)
+ pdata->devices[i] = ocp2scp_dev;
+
+ pdata->dev_cnt = dev_cnt;
+
+ pdev = omap_device_build(name, bus_id, oh, pdata, sizeof(*pdata), NULL,
+ 0, false);
+ if (IS_ERR(pdev)) {
+ pr_err("Could not build omap_device for %s %s\n",
+ name, oh_name);
+ kfree(pdata->devices);
+ kfree(pdata);
+ return;
+ }
+}
+#else
+static inline void omap_init_ocp2scp(void) { }
+#endif
+
/*-------------------------------------------------------------------------*/
static int __init omap2_init_devices(void)
@@ -640,6 +718,7 @@ static int __init omap2_init_devices(void)
omap_init_sham();
omap_init_aes();
omap_init_vout();
+ omap_init_ocp2scp();
return 0;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index b969ab1d258b..87cc6d058de2 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -422,6 +422,38 @@ static int _set_softreset(struct omap_hwmod *oh, u32 *v)
}
/**
+ * _wait_softreset_complete - wait for an OCP softreset to complete
+ * @oh: struct omap_hwmod * to wait on
+ *
+ * Wait until the IP block represented by @oh reports that its OCP
+ * softreset is complete. This can be triggered by software (see
+ * _ocp_softreset()) or by hardware upon returning from off-mode (one
+ * example is HSMMC). Waits for up to MAX_MODULE_SOFTRESET_WAIT
+ * microseconds. Returns the number of microseconds waited.
+ */
+static int _wait_softreset_complete(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_class_sysconfig *sysc;
+ u32 softrst_mask;
+ int c = 0;
+
+ sysc = oh->class->sysc;
+
+ if (sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
+ omap_test_timeout((omap_hwmod_read(oh, sysc->syss_offs)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+ else if (sysc->sysc_flags & SYSC_HAS_RESET_STATUS) {
+ softrst_mask = (0x1 << sysc->sysc_fields->srst_shift);
+ omap_test_timeout(!(omap_hwmod_read(oh, sysc->sysc_offs)
+ & softrst_mask),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+ }
+
+ return c;
+}
+
+/**
* _set_dmadisable: set OCP_SYSCONFIG.DMADISABLE bit in @v
* @oh: struct omap_hwmod *
*
@@ -1282,6 +1314,18 @@ static void _enable_sysc(struct omap_hwmod *oh)
if (!oh->class->sysc)
return;
+ /*
+ * Wait until reset has completed, this is needed as the IP
+ * block is reset automatically by hardware in some cases
+ * (off-mode for example), and the drivers require the
+ * IP to be ready when they access it
+ */
+ if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+ _enable_optional_clocks(oh);
+ _wait_softreset_complete(oh);
+ if (oh->flags & HWMOD_CONTROL_OPT_CLKS_IN_RESET)
+ _disable_optional_clocks(oh);
+
v = oh->_sysc_cache;
sf = oh->class->sysc->sysc_flags;
@@ -1804,7 +1848,7 @@ static int _am33xx_disable_module(struct omap_hwmod *oh)
*/
static int _ocp_softreset(struct omap_hwmod *oh)
{
- u32 v, softrst_mask;
+ u32 v;
int c = 0;
int ret = 0;
@@ -1834,19 +1878,7 @@ static int _ocp_softreset(struct omap_hwmod *oh)
if (oh->class->sysc->srst_udelay)
udelay(oh->class->sysc->srst_udelay);
- if (oh->class->sysc->sysc_flags & SYSS_HAS_RESET_STATUS)
- omap_test_timeout((omap_hwmod_read(oh,
- oh->class->sysc->syss_offs)
- & SYSS_RESETDONE_MASK),
- MAX_MODULE_SOFTRESET_WAIT, c);
- else if (oh->class->sysc->sysc_flags & SYSC_HAS_RESET_STATUS) {
- softrst_mask = (0x1 << oh->class->sysc->sysc_fields->srst_shift);
- omap_test_timeout(!(omap_hwmod_read(oh,
- oh->class->sysc->sysc_offs)
- & softrst_mask),
- MAX_MODULE_SOFTRESET_WAIT, c);
- }
-
+ c = _wait_softreset_complete(oh);
if (c == MAX_MODULE_SOFTRESET_WAIT)
pr_warning("omap_hwmod: %s: softreset failed (waited %d usec)\n",
oh->name, MAX_MODULE_SOFTRESET_WAIT);
@@ -2352,6 +2384,9 @@ static int __init _setup_reset(struct omap_hwmod *oh)
if (oh->_state != _HWMOD_STATE_INITIALIZED)
return -EINVAL;
+ if (oh->flags & HWMOD_EXT_OPT_MAIN_CLK)
+ return -EPERM;
+
if (oh->rst_lines_cnt == 0) {
r = _enable(oh);
if (r) {
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 652d0285bd6d..0b1249e00398 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/power/smartreflex.h>
+#include <linux/platform_data/omap_ocp2scp.h>
#include <plat/omap_hwmod.h>
#include <plat/i2c.h>
@@ -2125,6 +2126,14 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = {
.name = "mcpdm",
.class = &omap44xx_mcpdm_hwmod_class,
.clkdm_name = "abe_clkdm",
+ /*
+ * It's suspected that the McPDM requires an off-chip main
+ * functional clock, controlled via I2C. This IP block is
+ * currently reset very early during boot, before I2C is
+ * available, so it doesn't seem that we have any choice in
+ * the kernel other than to avoid resetting it.
+ */
+ .flags = HWMOD_EXT_OPT_MAIN_CLK,
.mpu_irqs = omap44xx_mcpdm_irqs,
.sdma_reqs = omap44xx_mcpdm_sdma_reqs,
.main_clk = "mcpdm_fck",
@@ -2681,6 +2690,32 @@ static struct omap_hwmod_class omap44xx_ocp2scp_hwmod_class = {
.sysc = &omap44xx_ocp2scp_sysc,
};
+/* ocp2scp dev_attr */
+static struct resource omap44xx_usb_phy_and_pll_addrs[] = {
+ {
+ .name = "usb_phy",
+ .start = 0x4a0ad080,
+ .end = 0x4a0ae000,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* XXX: Remove this once control module driver is in place */
+ .name = "ctrl_dev",
+ .start = 0x4a002300,
+ .end = 0x4a002303,
+ .flags = IORESOURCE_MEM,
+ },
+ { }
+};
+
+static struct omap_ocp2scp_dev ocp2scp_dev_attr[] = {
+ {
+ .drv_name = "omap-usb2",
+ .res = omap44xx_usb_phy_and_pll_addrs,
+ },
+ { }
+};
+
/* ocp2scp_usb_phy */
static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
.name = "ocp2scp_usb_phy",
@@ -2694,6 +2729,7 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
+ .dev_attr = ocp2scp_dev_attr,
};
/*
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 635e109f5ad3..a256135d8e48 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -73,6 +73,7 @@ void __init omap4_pmic_init(const char *pmic_type,
{
/* PMIC part*/
omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
+ omap_mux_init_signal("fref_clk0_out.sys_drm_msecure", OMAP_PIN_OUTPUT);
omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data);
/* Register additional devices on i2c1 bus if needed */
@@ -366,7 +367,7 @@ static struct regulator_init_data omap4_clk32kg_idata = {
};
static struct regulator_consumer_supply omap4_vdd1_supply[] = {
- REGULATOR_SUPPLY("vcc", "mpu.0"),
+ REGULATOR_SUPPLY("vcc", "cpu0"),
};
static struct regulator_consumer_supply omap4_vdd2_supply[] = {
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index 880249b17012..75878c37959b 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -264,7 +264,7 @@ static void __init omap_vc_i2c_init(struct voltagedomain *voltdm)
if (initialized) {
if (voltdm->pmic->i2c_high_speed != i2c_high_speed)
- pr_warn("%s: I2C config for vdd_%s does not match other channels (%u).",
+ pr_warn("%s: I2C config for vdd_%s does not match other channels (%u).\n",
__func__, voltdm->name, i2c_high_speed);
return;
}
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index 5ecbd17b5641..e2c6391863fe 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -28,6 +28,7 @@
#include <linux/mfd/asic3.h>
#include <linux/mtd/physmap.h>
#include <linux/pda_power.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/gpio-regulator.h>
@@ -556,7 +557,7 @@ static struct platform_device hx4700_lcd = {
*/
static struct platform_pwm_backlight_data backlight_data = {
- .pwm_id = 1,
+ .pwm_id = -1, /* Superseded by pwm_lookup */
.max_brightness = 200,
.dft_brightness = 100,
.pwm_period_ns = 30923,
@@ -571,6 +572,10 @@ static struct platform_device backlight = {
},
};
+static struct pwm_lookup hx4700_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.1", 0, "pwm-backlight", NULL),
+};
+
/*
* USB "Transceiver"
*/
@@ -872,6 +877,7 @@ static void __init hx4700_init(void)
pxa_set_stuart_info(NULL);
platform_add_devices(devices, ARRAY_SIZE(devices));
+ pwm_add_table(hx4700_pwm_lookup, ARRAY_SIZE(hx4700_pwm_lookup));
pxa_set_ficp_info(&ficp_info);
pxa27x_set_i2c_power_info(NULL);
diff --git a/arch/arm/mach-pxa/spitz_pm.c b/arch/arm/mach-pxa/spitz_pm.c
index 438f02fe122a..842596d4d31e 100644
--- a/arch/arm/mach-pxa/spitz_pm.c
+++ b/arch/arm/mach-pxa/spitz_pm.c
@@ -86,10 +86,7 @@ static void spitz_discharge1(int on)
gpio_set_value(SPITZ_GPIO_LED_GREEN, on);
}
-static unsigned long gpio18_config[] = {
- GPIO18_RDY,
- GPIO18_GPIO,
-};
+static unsigned long gpio18_config = GPIO18_GPIO;
static void spitz_presuspend(void)
{
@@ -112,7 +109,7 @@ static void spitz_presuspend(void)
PGSR3 &= ~SPITZ_GPIO_G3_STROBE_BIT;
PGSR2 |= GPIO_bit(SPITZ_GPIO_KEY_STROBE0);
- pxa2xx_mfp_config(&gpio18_config[0], 1);
+ pxa2xx_mfp_config(&gpio18_config, 1);
gpio_request_one(18, GPIOF_OUT_INIT_HIGH, "Unknown");
gpio_free(18);
@@ -131,7 +128,6 @@ static void spitz_presuspend(void)
static void spitz_postsuspend(void)
{
- pxa2xx_mfp_config(&gpio18_config[1], 1);
}
static int spitz_should_wakeup(unsigned int resume_on_alarm)
diff --git a/arch/arm/mach-u300/core.c b/arch/arm/mach-u300/core.c
index b8efac4daed8..ece8a2dfb814 100644
--- a/arch/arm/mach-u300/core.c
+++ b/arch/arm/mach-u300/core.c
@@ -1445,8 +1445,6 @@ static struct platform_device pinctrl_device = {
static struct u300_gpio_platform u300_gpio_plat = {
.ports = 7,
.gpio_base = 0,
- .gpio_irq_base = IRQ_U300_GPIO_BASE,
- .pinctrl_device = &pinctrl_device,
};
static struct platform_device gpio_device = {
@@ -1590,6 +1588,7 @@ static struct platform_device *platform_devs[] __initdata = {
&i2c1_device,
&keypad_device,
&rtc_device,
+ &pinctrl_device,
&gpio_device,
&nand_device,
&wdog_device,
@@ -1804,7 +1803,7 @@ MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
/* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
.atag_offset = 0x100,
.map_io = u300_map_io,
- .nr_irqs = NR_IRQS_U300,
+ .nr_irqs = 0,
.init_irq = u300_init_irq,
.handle_irq = vic_handle_irq,
.timer = &u300_timer,
diff --git a/arch/arm/mach-u300/include/mach/irqs.h b/arch/arm/mach-u300/include/mach/irqs.h
index e27425a63fa1..21d5e76a6cd3 100644
--- a/arch/arm/mach-u300/include/mach/irqs.h
+++ b/arch/arm/mach-u300/include/mach/irqs.h
@@ -12,79 +12,69 @@
#ifndef __MACH_IRQS_H
#define __MACH_IRQS_H
-#define IRQ_U300_INTCON0_START 1
-#define IRQ_U300_INTCON1_START 33
+#define IRQ_U300_INTCON0_START 32
+#define IRQ_U300_INTCON1_START 64
/* These are on INTCON0 - 30 lines */
-#define IRQ_U300_IRQ0_EXT 1
-#define IRQ_U300_IRQ1_EXT 2
-#define IRQ_U300_DMA 3
-#define IRQ_U300_VIDEO_ENC_0 4
-#define IRQ_U300_VIDEO_ENC_1 5
-#define IRQ_U300_AAIF_RX 6
-#define IRQ_U300_AAIF_TX 7
-#define IRQ_U300_AAIF_VGPIO 8
-#define IRQ_U300_AAIF_WAKEUP 9
-#define IRQ_U300_PCM_I2S0_FRAME 10
-#define IRQ_U300_PCM_I2S0_FIFO 11
-#define IRQ_U300_PCM_I2S1_FRAME 12
-#define IRQ_U300_PCM_I2S1_FIFO 13
-#define IRQ_U300_XGAM_GAMCON 14
-#define IRQ_U300_XGAM_CDI 15
-#define IRQ_U300_XGAM_CDICON 16
-#define IRQ_U300_XGAM_PDI 18
-#define IRQ_U300_XGAM_PDICON 19
-#define IRQ_U300_XGAM_GAMEACC 20
-#define IRQ_U300_XGAM_MCIDCT 21
-#define IRQ_U300_APEX 22
-#define IRQ_U300_UART0 23
-#define IRQ_U300_SPI 24
-#define IRQ_U300_TIMER_APP_OS 25
-#define IRQ_U300_TIMER_APP_DD 26
-#define IRQ_U300_TIMER_APP_GP1 27
-#define IRQ_U300_TIMER_APP_GP2 28
-#define IRQ_U300_TIMER_OS 29
-#define IRQ_U300_TIMER_MS 30
-#define IRQ_U300_KEYPAD_KEYBF 31
-#define IRQ_U300_KEYPAD_KEYBR 32
+#define IRQ_U300_IRQ0_EXT 32
+#define IRQ_U300_IRQ1_EXT 33
+#define IRQ_U300_DMA 34
+#define IRQ_U300_VIDEO_ENC_0 35
+#define IRQ_U300_VIDEO_ENC_1 36
+#define IRQ_U300_AAIF_RX 37
+#define IRQ_U300_AAIF_TX 38
+#define IRQ_U300_AAIF_VGPIO 39
+#define IRQ_U300_AAIF_WAKEUP 40
+#define IRQ_U300_PCM_I2S0_FRAME 41
+#define IRQ_U300_PCM_I2S0_FIFO 42
+#define IRQ_U300_PCM_I2S1_FRAME 43
+#define IRQ_U300_PCM_I2S1_FIFO 44
+#define IRQ_U300_XGAM_GAMCON 45
+#define IRQ_U300_XGAM_CDI 46
+#define IRQ_U300_XGAM_CDICON 47
+#define IRQ_U300_XGAM_PDI 49
+#define IRQ_U300_XGAM_PDICON 50
+#define IRQ_U300_XGAM_GAMEACC 51
+#define IRQ_U300_XGAM_MCIDCT 52
+#define IRQ_U300_APEX 53
+#define IRQ_U300_UART0 54
+#define IRQ_U300_SPI 55
+#define IRQ_U300_TIMER_APP_OS 56
+#define IRQ_U300_TIMER_APP_DD 57
+#define IRQ_U300_TIMER_APP_GP1 58
+#define IRQ_U300_TIMER_APP_GP2 59
+#define IRQ_U300_TIMER_OS 60
+#define IRQ_U300_TIMER_MS 61
+#define IRQ_U300_KEYPAD_KEYBF 62
+#define IRQ_U300_KEYPAD_KEYBR 63
/* These are on INTCON1 - 32 lines */
-#define IRQ_U300_GPIO_PORT0 33
-#define IRQ_U300_GPIO_PORT1 34
-#define IRQ_U300_GPIO_PORT2 35
+#define IRQ_U300_GPIO_PORT0 64
+#define IRQ_U300_GPIO_PORT1 65
+#define IRQ_U300_GPIO_PORT2 66
/* These are for DB3150, DB3200 and DB3350 */
-#define IRQ_U300_WDOG 36
-#define IRQ_U300_EVHIST 37
-#define IRQ_U300_MSPRO 38
-#define IRQ_U300_MMCSD_MCIINTR0 39
-#define IRQ_U300_MMCSD_MCIINTR1 40
-#define IRQ_U300_I2C0 41
-#define IRQ_U300_I2C1 42
-#define IRQ_U300_RTC 43
-#define IRQ_U300_NFIF 44
-#define IRQ_U300_NFIF2 45
+#define IRQ_U300_WDOG 67
+#define IRQ_U300_EVHIST 68
+#define IRQ_U300_MSPRO 69
+#define IRQ_U300_MMCSD_MCIINTR0 70
+#define IRQ_U300_MMCSD_MCIINTR1 71
+#define IRQ_U300_I2C0 72
+#define IRQ_U300_I2C1 73
+#define IRQ_U300_RTC 74
+#define IRQ_U300_NFIF 75
+#define IRQ_U300_NFIF2 76
/* The DB3350-specific interrupt lines */
-#define IRQ_U300_ISP_F0 46
-#define IRQ_U300_ISP_F1 47
-#define IRQ_U300_ISP_F2 48
-#define IRQ_U300_ISP_F3 49
-#define IRQ_U300_ISP_F4 50
-#define IRQ_U300_GPIO_PORT3 51
-#define IRQ_U300_SYSCON_PLL_LOCK 52
-#define IRQ_U300_UART1 53
-#define IRQ_U300_GPIO_PORT4 54
-#define IRQ_U300_GPIO_PORT5 55
-#define IRQ_U300_GPIO_PORT6 56
-#define U300_VIC_IRQS_END 57
-
-/* Maximum 8*7 GPIO lines */
-#ifdef CONFIG_PINCTRL_COH901
-#define IRQ_U300_GPIO_BASE (U300_VIC_IRQS_END)
-#define IRQ_U300_GPIO_END (IRQ_U300_GPIO_BASE + 56)
-#else
-#define IRQ_U300_GPIO_END (U300_VIC_IRQS_END)
-#endif
-
-#define NR_IRQS_U300 (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
+#define IRQ_U300_ISP_F0 77
+#define IRQ_U300_ISP_F1 78
+#define IRQ_U300_ISP_F2 79
+#define IRQ_U300_ISP_F3 80
+#define IRQ_U300_ISP_F4 81
+#define IRQ_U300_GPIO_PORT3 82
+#define IRQ_U300_SYSCON_PLL_LOCK 83
+#define IRQ_U300_UART1 84
+#define IRQ_U300_GPIO_PORT4 85
+#define IRQ_U300_GPIO_PORT5 86
+#define IRQ_U300_GPIO_PORT6 87
+#define U300_VIC_IRQS_END 88
#endif
diff --git a/arch/arm/mach-ux500/board-mop500-audio.c b/arch/arm/mach-ux500/board-mop500-audio.c
index 070629a95625..33631c9f1218 100644
--- a/arch/arm/mach-ux500/board-mop500-audio.c
+++ b/arch/arm/mach-ux500/board-mop500-audio.c
@@ -7,9 +7,8 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/gpio.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
-#include <plat/gpio-nomadik.h>
-#include <plat/pincfg.h>
#include <plat/ste_dma40.h>
#include <mach/devices.h>
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
index a267c6d30e37..c34d4efd0d5c 100644
--- a/arch/arm/mach-ux500/board-mop500-pins.c
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -9,10 +9,9 @@
#include <linux/bug.h>
#include <linux/string.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/mach-types.h>
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 416d436111f2..0a3dd601a400 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -37,13 +37,13 @@
#include <linux/of_platform.h>
#include <linux/leds.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
#include <plat/ste_dma40.h>
-#include <plat/gpio-nomadik.h>
#include <mach/hardware.h>
#include <mach/setup.h>
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index bcdfe6b1d453..91f028c1264a 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -17,14 +17,14 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/mfd/abx500/ab8500.h>
+#include <linux/platform_data/usb-musb-ux500.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/pmu.h>
#include <asm/mach/map.h>
-#include <plat/gpio-nomadik.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
-#include <linux/platform_data/usb-musb-ux500.h>
#include <mach/db8500-regs.h>
#include "devices-db8500.h"
@@ -158,7 +158,7 @@ static void __init db8500_add_gpios(struct device *parent)
dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
IRQ_DB8500_GPIO0, &pdata);
- dbx500_add_pinctrl(parent, "pinctrl-db8500");
+ dbx500_add_pinctrl(parent, "pinctrl-db8500", U8500_PRCMU_BASE);
}
static int usb_db8500_rx_dma_cfg[] = {
@@ -214,9 +214,6 @@ struct device * __init u8500_init_devices(struct ab8500_platform_data *ab8500)
db8500_add_gpios(parent);
db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
- platform_device_register_data(parent,
- "cpufreq-u8500", -1, NULL, 0);
-
for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
platform_devs[i]->dev.parent = parent;
@@ -236,9 +233,6 @@ struct device * __init u8500_of_init_devices(void)
db8500_add_usb(parent, usb_db8500_rx_dma_cfg, usb_db8500_tx_dma_cfg);
- platform_device_register_data(parent,
- "cpufreq-u8500", -1, NULL, 0);
-
u8500_dma40_device.dev.parent = parent;
/*
diff --git a/arch/arm/mach-ux500/devices-common.c b/arch/arm/mach-ux500/devices-common.c
index dfdd4a54668d..692a77a1c153 100644
--- a/arch/arm/mach-ux500/devices-common.c
+++ b/arch/arm/mach-ux500/devices-common.c
@@ -11,8 +11,7 @@
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
-
-#include <plat/gpio-nomadik.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
index 7fbf0ba336e1..96fa4ac89e2e 100644
--- a/arch/arm/mach-ux500/devices-common.h
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -129,12 +129,18 @@ void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
int irq, struct nmk_gpio_platform_data *pdata);
static inline void
-dbx500_add_pinctrl(struct device *parent, const char *name)
+dbx500_add_pinctrl(struct device *parent, const char *name,
+ resource_size_t base)
{
+ struct resource res[] = {
+ DEFINE_RES_MEM(base, SZ_8K),
+ };
struct platform_device_info pdevinfo = {
.parent = parent,
.name = name,
.id = -1,
+ .res = res,
+ .num_res = ARRAY_SIZE(res),
};
platform_device_register_full(&pdevinfo);
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 86b8b480634f..09c5233f4dfc 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -89,7 +89,7 @@ ENTRY(cpu_v6_dcache_clean_area)
mov pc, lr
/*
- * cpu_arm926_switch_mm(pgd_phys, tsk)
+ * cpu_v6_switch_mm(pgd_phys, tsk)
*
* Set the translation table base pointer to be pgd_phys
*
diff --git a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
deleted file mode 100644
index c08a54d9d889..000000000000
--- a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Structures and registers for GPIO access in the Nomadik SoC
- *
- * Copyright (C) 2008 STMicroelectronics
- * Author: Prafulla WADASKAR <prafulla.wadaskar@st.com>
- * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
- *
- * 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 __PLAT_NOMADIK_GPIO
-#define __PLAT_NOMADIK_GPIO
-
-/*
- * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving
- * the "gpio" namespace for generic and cross-machine functions
- */
-
-/* Register in the logic block */
-#define NMK_GPIO_DAT 0x00
-#define NMK_GPIO_DATS 0x04
-#define NMK_GPIO_DATC 0x08
-#define NMK_GPIO_PDIS 0x0c
-#define NMK_GPIO_DIR 0x10
-#define NMK_GPIO_DIRS 0x14
-#define NMK_GPIO_DIRC 0x18
-#define NMK_GPIO_SLPC 0x1c
-#define NMK_GPIO_AFSLA 0x20
-#define NMK_GPIO_AFSLB 0x24
-#define NMK_GPIO_LOWEMI 0x28
-
-#define NMK_GPIO_RIMSC 0x40
-#define NMK_GPIO_FIMSC 0x44
-#define NMK_GPIO_IS 0x48
-#define NMK_GPIO_IC 0x4c
-#define NMK_GPIO_RWIMSC 0x50
-#define NMK_GPIO_FWIMSC 0x54
-#define NMK_GPIO_WKS 0x58
-
-/* Alternate functions: function C is set in hw by setting both A and B */
-#define NMK_GPIO_ALT_GPIO 0
-#define NMK_GPIO_ALT_A 1
-#define NMK_GPIO_ALT_B 2
-#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B)
-
-#define NMK_GPIO_ALT_CX_SHIFT 2
-#define NMK_GPIO_ALT_C1 ((1<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
-#define NMK_GPIO_ALT_C2 ((2<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
-#define NMK_GPIO_ALT_C3 ((3<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
-#define NMK_GPIO_ALT_C4 ((4<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
-
-/* Pull up/down values */
-enum nmk_gpio_pull {
- NMK_GPIO_PULL_NONE,
- NMK_GPIO_PULL_UP,
- NMK_GPIO_PULL_DOWN,
-};
-
-/* Sleep mode */
-enum nmk_gpio_slpm {
- NMK_GPIO_SLPM_INPUT,
- NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
- NMK_GPIO_SLPM_NOCHANGE,
- NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
-};
-
-extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
-extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
-#ifdef CONFIG_PINCTRL_NOMADIK
-extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
-#else
-static inline int nmk_gpio_set_mode(int gpio, int gpio_mode)
-{
- return -ENODEV;
-}
-#endif
-extern int nmk_gpio_get_mode(int gpio);
-
-extern void nmk_gpio_wakeups_suspend(void);
-extern void nmk_gpio_wakeups_resume(void);
-
-extern void nmk_gpio_clocks_enable(void);
-extern void nmk_gpio_clocks_disable(void);
-
-extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
-
-/*
- * Platform data to register a block: only the initial gpio/irq number.
- */
-struct nmk_gpio_platform_data {
- char *name;
- int first_gpio;
- int first_irq;
- int num_gpio;
- u32 (*get_secondary_status)(unsigned int bank);
- void (*set_ioforce)(bool enable);
- bool supports_sleepmode;
-};
-
-#endif /* __PLAT_NOMADIK_GPIO */
diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
index a5683a84c6ee..6013831a043e 100644
--- a/arch/arm/plat-omap/i2c.c
+++ b/arch/arm/plat-omap/i2c.c
@@ -26,12 +26,14 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/i2c-omap.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <mach/irqs.h>
#include <plat/i2c.h>
+#include <plat/omap-pm.h>
#include <plat/omap_device.h>
#define OMAP_I2C_SIZE 0x3f
@@ -127,6 +129,16 @@ static inline int omap1_i2c_add_bus(int bus_id)
#ifdef CONFIG_ARCH_OMAP2PLUS
+/*
+ * XXX This function is a temporary compatibility wrapper - only
+ * needed until the I2C driver can be converted to call
+ * omap_pm_set_max_dev_wakeup_lat() and handle a return code.
+ */
+static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t)
+{
+ omap_pm_set_max_mpu_wakeup_lat(dev, t);
+}
+
static inline int omap2_i2c_add_bus(int bus_id)
{
int l;
@@ -158,6 +170,15 @@ static inline int omap2_i2c_add_bus(int bus_id)
dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr;
pdata->flags = dev_attr->flags;
+ /*
+ * When waiting for completion of a i2c transfer, we need to
+ * set a wake up latency constraint for the MPU. This is to
+ * ensure quick enough wakeup from idle, when transfer
+ * completes.
+ * Only omap3 has support for constraints
+ */
+ if (cpu_is_omap34xx())
+ pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;
pdev = omap_device_build(name, bus_id, oh, pdata,
sizeof(struct omap_i2c_bus_platform_data),
NULL, 0, 0);
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index 8b4e4f2da2f5..346af5b490be 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -126,6 +126,7 @@ struct omap_mmc_platform_data {
/* we can put the features above into this variable */
#define HSMMC_HAS_PBIAS (1 << 0)
#define HSMMC_HAS_UPDATED_RESET (1 << 1)
+#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
unsigned features;
int switch_pin; /* gpio (card detect) */
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index b3349f7b1a2c..1db029438022 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -443,6 +443,11 @@ struct omap_hwmod_omap4_prcm {
* in order to complete the reset. Optional clocks will be disabled
* again after the reset.
* HWMOD_16BIT_REG: Module has 16bit registers
+ * HWMOD_EXT_OPT_MAIN_CLK: The only main functional clock source for
+ * this IP block comes from an off-chip source and is not always
+ * enabled. This prevents the hwmod code from being able to
+ * enable and reset the IP block early. XXX Eventually it should
+ * be possible to query the clock framework for this information.
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -453,6 +458,7 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_NO_IDLEST (1 << 6)
#define HWMOD_CONTROL_OPT_CLKS_IN_RESET (1 << 7)
#define HWMOD_16BIT_REG (1 << 8)
+#define HWMOD_EXT_OPT_MAIN_CLK (1 << 9)
/*
* omap_hwmod._int_flags definitions
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index db98e7021f0d..0abd1c469887 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -473,12 +473,13 @@ int s3c2410_dma_enqueue(enum dma_ch channel, void *id,
pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
chan->number, __func__, buf);
- if (chan->end == NULL)
+ if (chan->end == NULL) {
pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
chan->number, __func__, chan);
-
- chan->end->next = buf;
- chan->end = buf;
+ } else {
+ chan->end->next = buf;
+ chan->end = buf;
+ }
}
/* if necessary, update the next buffer field */
diff --git a/arch/arm/tools/Makefile b/arch/arm/tools/Makefile
index cd60a81163e9..32d05c8219dc 100644
--- a/arch/arm/tools/Makefile
+++ b/arch/arm/tools/Makefile
@@ -5,6 +5,6 @@
#
include/generated/mach-types.h: $(src)/gen-mach-types $(src)/mach-types
- $(kecho) ' Generating $@'
+ @$(kecho) ' Generating $@'
@mkdir -p $(dir $@)
$(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 54f6116697f7..d2f05a608274 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -222,7 +222,7 @@ extern void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot
extern void __iounmap(volatile void __iomem *addr);
#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY)
-#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_XN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
+#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE))
#define PROT_NORMAL_NC (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC))
#define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE))
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 0f3b4581d925..75fd13d289b9 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -38,7 +38,8 @@
#define PMD_SECT_S (_AT(pmdval_t, 3) << 8)
#define PMD_SECT_AF (_AT(pmdval_t, 1) << 10)
#define PMD_SECT_NG (_AT(pmdval_t, 1) << 11)
-#define PMD_SECT_XN (_AT(pmdval_t, 1) << 54)
+#define PMD_SECT_PXN (_AT(pmdval_t, 1) << 53)
+#define PMD_SECT_UXN (_AT(pmdval_t, 1) << 54)
/*
* AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers).
@@ -57,7 +58,8 @@
#define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */
#define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */
#define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */
-#define PTE_XN (_AT(pteval_t, 1) << 54) /* XN */
+#define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */
+#define PTE_UXN (_AT(pteval_t, 1) << 54) /* User XN */
/*
* AttrIndx[2:0] encoding (mapping attributes defined in the MAIR* registers).
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 8960239be722..14aba2db6776 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -62,23 +62,23 @@ extern pgprot_t pgprot_default;
#define _MOD_PROT(p, b) __pgprot(pgprot_val(p) | (b))
-#define PAGE_NONE _MOD_PROT(pgprot_default, PTE_NG | PTE_XN | PTE_RDONLY)
-#define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN)
-#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG)
-#define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
-#define PAGE_COPY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY)
-#define PAGE_READONLY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
-#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_RDONLY)
-#define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_XN | PTE_DIRTY)
-#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_DIRTY)
-
-#define __PAGE_NONE __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_XN | PTE_RDONLY)
-#define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN)
-#define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG)
-#define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
-#define __PAGE_COPY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY)
-#define __PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_XN | PTE_RDONLY)
-#define __PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_RDONLY)
+#define PAGE_NONE _MOD_PROT(pgprot_default, PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define PAGE_SHARED _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
+#define PAGE_SHARED_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
+#define PAGE_COPY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define PAGE_COPY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
+#define PAGE_READONLY _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define PAGE_READONLY_EXEC _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
+#define PAGE_KERNEL _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY)
+#define PAGE_KERNEL_EXEC _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY)
+
+#define __PAGE_NONE __pgprot(_PAGE_DEFAULT | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define __PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
+#define __PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
+#define __PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define __PAGE_COPY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
+#define __PAGE_READONLY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
+#define __PAGE_READONLY_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
#endif /* __ASSEMBLY__ */
@@ -130,10 +130,10 @@ extern struct page *empty_zero_page;
#define pte_young(pte) (pte_val(pte) & PTE_AF)
#define pte_special(pte) (pte_val(pte) & PTE_SPECIAL)
#define pte_write(pte) (!(pte_val(pte) & PTE_RDONLY))
-#define pte_exec(pte) (!(pte_val(pte) & PTE_XN))
+#define pte_exec(pte) (!(pte_val(pte) & PTE_UXN))
#define pte_present_exec_user(pte) \
- ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_XN)) == \
+ ((pte_val(pte) & (PTE_VALID | PTE_USER | PTE_UXN)) == \
(PTE_VALID | PTE_USER))
#define PTE_BIT_FUNC(fn,op) \
@@ -262,7 +262,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{
- const pteval_t mask = PTE_USER | PTE_XN | PTE_RDONLY;
+ const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY;
pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
return pte;
}
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index 6d909faebf28..656a6f291a35 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -392,7 +392,7 @@ __SYSCALL(367, sys_fanotify_init)
__SYSCALL(368, compat_sys_fanotify_mark_wrapper)
__SYSCALL(369, sys_prlimit64)
__SYSCALL(370, sys_name_to_handle_at)
-__SYSCALL(371, sys_open_by_handle_at)
+__SYSCALL(371, compat_sys_open_by_handle_at)
__SYSCALL(372, sys_clock_adjtime)
__SYSCALL(373, sys_syncfs)
diff --git a/arch/c6x/include/asm/setup.h b/arch/c6x/include/asm/setup.h
new file mode 100644
index 000000000000..ecead15872a6
--- /dev/null
+++ b/arch/c6x/include/asm/setup.h
@@ -0,0 +1,33 @@
+/*
+ * Port on Texas Instruments TMS320C6x architecture
+ *
+ * Copyright (C) 2004, 2009, 2010 2011 Texas Instruments Incorporated
+ * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_C6X_SETUP_H
+#define _ASM_C6X_SETUP_H
+
+#include <uapi/asm/setup.h>
+
+#ifndef __ASSEMBLY__
+extern char c6x_command_line[COMMAND_LINE_SIZE];
+
+extern int c6x_add_memory(phys_addr_t start, unsigned long size);
+
+extern unsigned long ram_start;
+extern unsigned long ram_end;
+
+extern int c6x_num_cores;
+extern unsigned int c6x_silicon_rev;
+extern unsigned int c6x_devstat;
+extern unsigned char c6x_fuse_mac[6];
+
+extern void machine_init(unsigned long dt_ptr);
+extern void time_init(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASM_C6X_SETUP_H */
diff --git a/arch/c6x/include/uapi/asm/Kbuild b/arch/c6x/include/uapi/asm/Kbuild
index c312b424c433..e9bc2b2b8147 100644
--- a/arch/c6x/include/uapi/asm/Kbuild
+++ b/arch/c6x/include/uapi/asm/Kbuild
@@ -1,6 +1,8 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
+generic-y += kvm_para.h
+
header-y += byteorder.h
header-y += kvm_para.h
header-y += ptrace.h
diff --git a/arch/c6x/include/uapi/asm/kvm_para.h b/arch/c6x/include/uapi/asm/kvm_para.h
deleted file mode 100644
index 14fab8f0b957..000000000000
--- a/arch/c6x/include/uapi/asm/kvm_para.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
diff --git a/arch/c6x/include/uapi/asm/setup.h b/arch/c6x/include/uapi/asm/setup.h
index a01e31896fa9..ad9ac97a8dad 100644
--- a/arch/c6x/include/uapi/asm/setup.h
+++ b/arch/c6x/include/uapi/asm/setup.h
@@ -1,33 +1,6 @@
-/*
- * Port on Texas Instruments TMS320C6x architecture
- *
- * Copyright (C) 2004, 2009, 2010 2011 Texas Instruments Incorporated
- * Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef _ASM_C6X_SETUP_H
-#define _ASM_C6X_SETUP_H
+#ifndef _UAPI_ASM_C6X_SETUP_H
+#define _UAPI_ASM_C6X_SETUP_H
#define COMMAND_LINE_SIZE 1024
-#ifndef __ASSEMBLY__
-extern char c6x_command_line[COMMAND_LINE_SIZE];
-
-extern int c6x_add_memory(phys_addr_t start, unsigned long size);
-
-extern unsigned long ram_start;
-extern unsigned long ram_end;
-
-extern int c6x_num_cores;
-extern unsigned int c6x_silicon_rev;
-extern unsigned int c6x_devstat;
-extern unsigned char c6x_fuse_mac[6];
-
-extern void machine_init(unsigned long dt_ptr);
-extern void time_init(void);
-
-#endif /* !__ASSEMBLY__ */
-#endif /* _ASM_C6X_SETUP_H */
+#endif /* _UAPI_ASM_C6X_SETUP_H */
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
index 5449c36018fe..0ed6157dd256 100644
--- a/arch/c6x/kernel/entry.S
+++ b/arch/c6x/kernel/entry.S
@@ -277,6 +277,8 @@ work_rescheduled:
[A1] BNOP .S1 work_resched,5
work_notifysig:
+ ;; enable interrupts for do_notify_resume()
+ UNMASK_INT B2
B .S2 do_notify_resume
LDW .D2T1 *+SP(REGS__END+8),A6 ; syscall flag
ADDKPC .S2 resume_userspace,B3,1
@@ -427,8 +429,7 @@ ENTRY(ret_from_kernel_execve)
ENDPROC(ret_from_kernel_execve)
;;
- ;; These are the interrupt handlers, responsible for calling __do_IRQ()
- ;; int6 is used for syscalls (see _system_call entry)
+ ;; These are the interrupt handlers, responsible for calling c6x_do_IRQ()
;;
.macro SAVE_ALL_INT
SAVE_ALL IRP,ITSR
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index acd5b68e8871..082e383c1b6f 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -637,7 +637,6 @@ mem_init (void)
high_memory = __va(max_low_pfn * PAGE_SIZE);
- reset_zone_present_pages();
for_each_online_pgdat(pgdat)
if (pgdat->bdata->node_bootmem_map)
totalram_pages += free_all_bootmem_node(pgdat);
diff --git a/arch/m68k/include/asm/signal.h b/arch/m68k/include/asm/signal.h
index 67e489d8d1bd..2df26b57c26a 100644
--- a/arch/m68k/include/asm/signal.h
+++ b/arch/m68k/include/asm/signal.h
@@ -41,7 +41,7 @@ struct k_sigaction {
static inline void sigaddset(sigset_t *set, int _sig)
{
asm ("bfset %0{%1,#1}"
- : "+od" (*set)
+ : "+o" (*set)
: "id" ((_sig - 1) ^ 31)
: "cc");
}
@@ -49,7 +49,7 @@ static inline void sigaddset(sigset_t *set, int _sig)
static inline void sigdelset(sigset_t *set, int _sig)
{
asm ("bfclr %0{%1,#1}"
- : "+od" (*set)
+ : "+o" (*set)
: "id" ((_sig - 1) ^ 31)
: "cc");
}
@@ -65,7 +65,7 @@ static inline int __gen_sigismember(sigset_t *set, int _sig)
int ret;
asm ("bfextu %1{%2,#1},%0"
: "=d" (ret)
- : "od" (*set), "id" ((_sig-1) ^ 31)
+ : "o" (*set), "id" ((_sig-1) ^ 31)
: "cc");
return ret;
}
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 3847e5b9c601..3903e3d11f5a 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -111,7 +111,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1))
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1) == -EFAULT)
goto badframe;
return rval;
diff --git a/arch/mips/cavium-octeon/executive/cvmx-l2c.c b/arch/mips/cavium-octeon/executive/cvmx-l2c.c
index d38246e33ddb..9f883bf76953 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-l2c.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-l2c.c
@@ -30,6 +30,7 @@
* measurement, and debugging facilities.
*/
+#include <linux/irqflags.h>
#include <asm/octeon/cvmx.h>
#include <asm/octeon/cvmx-l2c.h>
#include <asm/octeon/cvmx-spinlock.h>
diff --git a/arch/mips/fw/arc/misc.c b/arch/mips/fw/arc/misc.c
index 7cf80ca2c1d2..f9f5307434c2 100644
--- a/arch/mips/fw/arc/misc.c
+++ b/arch/mips/fw/arc/misc.c
@@ -11,6 +11,7 @@
*/
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/irqflags.h>
#include <asm/bcache.h>
diff --git a/arch/mips/include/asm/bitops.h b/arch/mips/include/asm/bitops.h
index 82ad35ce2b45..46ac73abd5ee 100644
--- a/arch/mips/include/asm/bitops.h
+++ b/arch/mips/include/asm/bitops.h
@@ -14,7 +14,6 @@
#endif
#include <linux/compiler.h>
-#include <linux/irqflags.h>
#include <linux/types.h>
#include <asm/barrier.h>
#include <asm/byteorder.h> /* sigh ... */
@@ -44,6 +43,24 @@
#define smp_mb__before_clear_bit() smp_mb__before_llsc()
#define smp_mb__after_clear_bit() smp_llsc_mb()
+
+/*
+ * These are the "slower" versions of the functions and are in bitops.c.
+ * These functions call raw_local_irq_{save,restore}().
+ */
+void __mips_set_bit(unsigned long nr, volatile unsigned long *addr);
+void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr);
+void __mips_change_bit(unsigned long nr, volatile unsigned long *addr);
+int __mips_test_and_set_bit(unsigned long nr,
+ volatile unsigned long *addr);
+int __mips_test_and_set_bit_lock(unsigned long nr,
+ volatile unsigned long *addr);
+int __mips_test_and_clear_bit(unsigned long nr,
+ volatile unsigned long *addr);
+int __mips_test_and_change_bit(unsigned long nr,
+ volatile unsigned long *addr);
+
+
/*
* set_bit - Atomically set a bit in memory
* @nr: the bit to set
@@ -57,7 +74,7 @@
static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
{
unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
unsigned long temp;
if (kernel_uses_llsc && R10000_LLSC_WAR) {
@@ -92,17 +109,8 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
: "=&r" (temp), "+m" (*m)
: "ir" (1UL << bit));
} while (unlikely(!temp));
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- *a |= mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ __mips_set_bit(nr, addr);
}
/*
@@ -118,7 +126,7 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *addr)
static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
{
unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
unsigned long temp;
if (kernel_uses_llsc && R10000_LLSC_WAR) {
@@ -153,17 +161,8 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *addr)
: "=&r" (temp), "+m" (*m)
: "ir" (~(1UL << bit)));
} while (unlikely(!temp));
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- *a &= ~mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ __mips_clear_bit(nr, addr);
}
/*
@@ -191,7 +190,7 @@ static inline void clear_bit_unlock(unsigned long nr, volatile unsigned long *ad
*/
static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
{
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
if (kernel_uses_llsc && R10000_LLSC_WAR) {
unsigned long *m = ((unsigned long *) addr) + (nr >> SZLONG_LOG);
@@ -220,17 +219,8 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
: "=&r" (temp), "+m" (*m)
: "ir" (1UL << bit));
} while (unlikely(!temp));
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- *a ^= mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ __mips_change_bit(nr, addr);
}
/*
@@ -244,7 +234,7 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *addr)
static inline int test_and_set_bit(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
unsigned long res;
smp_mb__before_llsc();
@@ -281,18 +271,8 @@ static inline int test_and_set_bit(unsigned long nr,
} while (unlikely(!res));
res = temp & (1UL << bit);
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- res = (mask & *a);
- *a |= mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ res = __mips_test_and_set_bit(nr, addr);
smp_llsc_mb();
@@ -310,7 +290,7 @@ static inline int test_and_set_bit(unsigned long nr,
static inline int test_and_set_bit_lock(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
unsigned long res;
if (kernel_uses_llsc && R10000_LLSC_WAR) {
@@ -345,18 +325,8 @@ static inline int test_and_set_bit_lock(unsigned long nr,
} while (unlikely(!res));
res = temp & (1UL << bit);
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- res = (mask & *a);
- *a |= mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ res = __mips_test_and_set_bit_lock(nr, addr);
smp_llsc_mb();
@@ -373,7 +343,7 @@ static inline int test_and_set_bit_lock(unsigned long nr,
static inline int test_and_clear_bit(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
unsigned long res;
smp_mb__before_llsc();
@@ -428,18 +398,8 @@ static inline int test_and_clear_bit(unsigned long nr,
} while (unlikely(!res));
res = temp & (1UL << bit);
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- res = (mask & *a);
- *a &= ~mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ res = __mips_test_and_clear_bit(nr, addr);
smp_llsc_mb();
@@ -457,7 +417,7 @@ static inline int test_and_clear_bit(unsigned long nr,
static inline int test_and_change_bit(unsigned long nr,
volatile unsigned long *addr)
{
- unsigned short bit = nr & SZLONG_MASK;
+ int bit = nr & SZLONG_MASK;
unsigned long res;
smp_mb__before_llsc();
@@ -494,18 +454,8 @@ static inline int test_and_change_bit(unsigned long nr,
} while (unlikely(!res));
res = temp & (1UL << bit);
- } else {
- volatile unsigned long *a = addr;
- unsigned long mask;
- unsigned long flags;
-
- a += nr >> SZLONG_LOG;
- mask = 1UL << bit;
- raw_local_irq_save(flags);
- res = (mask & *a);
- *a ^= mask;
- raw_local_irq_restore(flags);
- }
+ } else
+ res = __mips_test_and_change_bit(nr, addr);
smp_llsc_mb();
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index 58277e0e9cd4..3c5d1464b7bd 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -290,7 +290,7 @@ struct compat_shmid64_ds {
static inline int is_compat_task(void)
{
- return test_thread_flag(TIF_32BIT);
+ return test_thread_flag(TIF_32BIT_ADDR);
}
#endif /* _ASM_COMPAT_H */
diff --git a/arch/mips/include/asm/hugetlb.h b/arch/mips/include/asm/hugetlb.h
index bd94946a18f3..ef99db994c2f 100644
--- a/arch/mips/include/asm/hugetlb.h
+++ b/arch/mips/include/asm/hugetlb.h
@@ -95,7 +95,17 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
pte_t *ptep, pte_t pte,
int dirty)
{
- return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+ int changed = !pte_same(*ptep, pte);
+
+ if (changed) {
+ set_pte_at(vma->vm_mm, addr, ptep, pte);
+ /*
+ * There could be some standard sized pages in there,
+ * get them all.
+ */
+ flush_tlb_range(vma, addr, addr + HPAGE_SIZE);
+ }
+ return changed;
}
static inline pte_t huge_ptep_get(pte_t *ptep)
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 29d9c23c20c7..ff2e0345e013 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -15,6 +15,7 @@
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/irqflags.h>
#include <asm/addrspace.h>
#include <asm/bug.h>
diff --git a/arch/mips/include/asm/irqflags.h b/arch/mips/include/asm/irqflags.h
index 309cbcd6909c..9f3384c789d7 100644
--- a/arch/mips/include/asm/irqflags.h
+++ b/arch/mips/include/asm/irqflags.h
@@ -16,83 +16,13 @@
#include <linux/compiler.h>
#include <asm/hazards.h>
-__asm__(
- " .macro arch_local_irq_enable \n"
- " .set push \n"
- " .set reorder \n"
- " .set noat \n"
-#ifdef CONFIG_MIPS_MT_SMTC
- " mfc0 $1, $2, 1 # SMTC - clear TCStatus.IXMT \n"
- " ori $1, 0x400 \n"
- " xori $1, 0x400 \n"
- " mtc0 $1, $2, 1 \n"
-#elif defined(CONFIG_CPU_MIPSR2)
- " ei \n"
-#else
- " mfc0 $1,$12 \n"
- " ori $1,0x1f \n"
- " xori $1,0x1e \n"
- " mtc0 $1,$12 \n"
-#endif
- " irq_enable_hazard \n"
- " .set pop \n"
- " .endm");
+#if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC)
-extern void smtc_ipi_replay(void);
-
-static inline void arch_local_irq_enable(void)
-{
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * SMTC kernel needs to do a software replay of queued
- * IPIs, at the cost of call overhead on each local_irq_enable()
- */
- smtc_ipi_replay();
-#endif
- __asm__ __volatile__(
- "arch_local_irq_enable"
- : /* no outputs */
- : /* no inputs */
- : "memory");
-}
-
-
-/*
- * For cli() we have to insert nops to make sure that the new value
- * has actually arrived in the status register before the end of this
- * macro.
- * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
- * no nops at all.
- */
-/*
- * For TX49, operating only IE bit is not enough.
- *
- * If mfc0 $12 follows store and the mfc0 is last instruction of a
- * page and fetching the next instruction causes TLB miss, the result
- * of the mfc0 might wrongly contain EXL bit.
- *
- * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008
- *
- * Workaround: mask EXL bit of the result or place a nop before mfc0.
- */
__asm__(
" .macro arch_local_irq_disable\n"
" .set push \n"
" .set noat \n"
-#ifdef CONFIG_MIPS_MT_SMTC
- " mfc0 $1, $2, 1 \n"
- " ori $1, 0x400 \n"
- " .set noreorder \n"
- " mtc0 $1, $2, 1 \n"
-#elif defined(CONFIG_CPU_MIPSR2)
" di \n"
-#else
- " mfc0 $1,$12 \n"
- " ori $1,0x1f \n"
- " xori $1,0x1f \n"
- " .set noreorder \n"
- " mtc0 $1,$12 \n"
-#endif
" irq_disable_hazard \n"
" .set pop \n"
" .endm \n");
@@ -106,46 +36,14 @@ static inline void arch_local_irq_disable(void)
: "memory");
}
-__asm__(
- " .macro arch_local_save_flags flags \n"
- " .set push \n"
- " .set reorder \n"
-#ifdef CONFIG_MIPS_MT_SMTC
- " mfc0 \\flags, $2, 1 \n"
-#else
- " mfc0 \\flags, $12 \n"
-#endif
- " .set pop \n"
- " .endm \n");
-
-static inline unsigned long arch_local_save_flags(void)
-{
- unsigned long flags;
- asm volatile("arch_local_save_flags %0" : "=r" (flags));
- return flags;
-}
__asm__(
" .macro arch_local_irq_save result \n"
" .set push \n"
" .set reorder \n"
" .set noat \n"
-#ifdef CONFIG_MIPS_MT_SMTC
- " mfc0 \\result, $2, 1 \n"
- " ori $1, \\result, 0x400 \n"
- " .set noreorder \n"
- " mtc0 $1, $2, 1 \n"
- " andi \\result, \\result, 0x400 \n"
-#elif defined(CONFIG_CPU_MIPSR2)
" di \\result \n"
" andi \\result, 1 \n"
-#else
- " mfc0 \\result, $12 \n"
- " ori $1, \\result, 0x1f \n"
- " xori $1, 0x1f \n"
- " .set noreorder \n"
- " mtc0 $1, $12 \n"
-#endif
" irq_disable_hazard \n"
" .set pop \n"
" .endm \n");
@@ -160,61 +58,37 @@ static inline unsigned long arch_local_irq_save(void)
return flags;
}
+
__asm__(
" .macro arch_local_irq_restore flags \n"
" .set push \n"
" .set noreorder \n"
" .set noat \n"
-#ifdef CONFIG_MIPS_MT_SMTC
- "mfc0 $1, $2, 1 \n"
- "andi \\flags, 0x400 \n"
- "ori $1, 0x400 \n"
- "xori $1, 0x400 \n"
- "or \\flags, $1 \n"
- "mtc0 \\flags, $2, 1 \n"
-#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
+#if defined(CONFIG_IRQ_CPU)
/*
* Slow, but doesn't suffer from a relatively unlikely race
* condition we're having since days 1.
*/
" beqz \\flags, 1f \n"
- " di \n"
+ " di \n"
" ei \n"
"1: \n"
-#elif defined(CONFIG_CPU_MIPSR2)
+#else
/*
* Fast, dangerous. Life is fun, life is good.
*/
" mfc0 $1, $12 \n"
" ins $1, \\flags, 0, 1 \n"
" mtc0 $1, $12 \n"
-#else
- " mfc0 $1, $12 \n"
- " andi \\flags, 1 \n"
- " ori $1, 0x1f \n"
- " xori $1, 0x1f \n"
- " or \\flags, $1 \n"
- " mtc0 \\flags, $12 \n"
#endif
" irq_disable_hazard \n"
" .set pop \n"
" .endm \n");
-
static inline void arch_local_irq_restore(unsigned long flags)
{
unsigned long __tmp1;
-#ifdef CONFIG_MIPS_MT_SMTC
- /*
- * SMTC kernel needs to do a software replay of queued
- * IPIs, at the cost of branch and call overhead on each
- * local_irq_restore()
- */
- if (unlikely(!(flags & 0x0400)))
- smtc_ipi_replay();
-#endif
-
__asm__ __volatile__(
"arch_local_irq_restore\t%0"
: "=r" (__tmp1)
@@ -232,6 +106,75 @@ static inline void __arch_local_irq_restore(unsigned long flags)
: "0" (flags)
: "memory");
}
+#else
+/* Functions that require preempt_{dis,en}able() are in mips-atomic.c */
+void arch_local_irq_disable(void);
+unsigned long arch_local_irq_save(void);
+void arch_local_irq_restore(unsigned long flags);
+void __arch_local_irq_restore(unsigned long flags);
+#endif /* if defined(CONFIG_CPU_MIPSR2) && !defined(CONFIG_MIPS_MT_SMTC) */
+
+
+__asm__(
+ " .macro arch_local_irq_enable \n"
+ " .set push \n"
+ " .set reorder \n"
+ " .set noat \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+ " mfc0 $1, $2, 1 # SMTC - clear TCStatus.IXMT \n"
+ " ori $1, 0x400 \n"
+ " xori $1, 0x400 \n"
+ " mtc0 $1, $2, 1 \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+ " ei \n"
+#else
+ " mfc0 $1,$12 \n"
+ " ori $1,0x1f \n"
+ " xori $1,0x1e \n"
+ " mtc0 $1,$12 \n"
+#endif
+ " irq_enable_hazard \n"
+ " .set pop \n"
+ " .endm");
+
+extern void smtc_ipi_replay(void);
+
+static inline void arch_local_irq_enable(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC kernel needs to do a software replay of queued
+ * IPIs, at the cost of call overhead on each local_irq_enable()
+ */
+ smtc_ipi_replay();
+#endif
+ __asm__ __volatile__(
+ "arch_local_irq_enable"
+ : /* no outputs */
+ : /* no inputs */
+ : "memory");
+}
+
+
+__asm__(
+ " .macro arch_local_save_flags flags \n"
+ " .set push \n"
+ " .set reorder \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+ " mfc0 \\flags, $2, 1 \n"
+#else
+ " mfc0 \\flags, $12 \n"
+#endif
+ " .set pop \n"
+ " .endm \n");
+
+static inline unsigned long arch_local_save_flags(void)
+{
+ unsigned long flags;
+ asm volatile("arch_local_save_flags %0" : "=r" (flags));
+ return flags;
+}
+
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
@@ -245,7 +188,7 @@ static inline int arch_irqs_disabled_flags(unsigned long flags)
#endif
}
-#endif
+#endif /* #ifndef __ASSEMBLY__ */
/*
* Do the CPU's IRQ-state tracing from assembly code.
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index 8debe9e91754..18806a52061c 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -112,12 +112,6 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define TIF_LOAD_WATCH 25 /* If set, load watch registers */
#define TIF_SYSCALL_TRACE 31 /* syscall trace active */
-#ifdef CONFIG_MIPS32_O32
-#define TIF_32BIT TIF_32BIT_REGS
-#elif defined(CONFIG_MIPS32_N32)
-#define TIF_32BIT _TIF_32BIT_ADDR
-#endif /* CONFIG_MIPS32_O32 */
-
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index b1fb7af3c350..cce3782c96c9 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -510,7 +510,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
c->cputype = CPU_R3000A;
__cpu_name[cpu] = "R3000A";
}
- break;
} else {
c->cputype = CPU_R3000;
__cpu_name[cpu] = "R3000";
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index a6c133212003..9b00362f32f6 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -36,6 +36,11 @@ FEXPORT(ret_from_exception)
FEXPORT(ret_from_irq)
LONG_S s0, TI_REGS($28)
FEXPORT(__ret_from_irq)
+/*
+ * We can be coming here from a syscall done in the kernel space,
+ * e.g. a failed kernel_execve().
+ */
+resume_userspace_check:
LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
andi t0, t0, KU_USER
beqz t0, resume_kernel
@@ -162,7 +167,7 @@ work_notifysig: # deal with pending signals and
move a0, sp
li a1, 0
jal do_notify_resume # a2 already loaded
- j resume_userspace
+ j resume_userspace_check
FEXPORT(syscall_exit_partial)
local_irq_disable # make sure need_resched doesn't
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f6ba8381ee01..86ec03f0e00c 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -397,14 +397,14 @@ EXPORT(sysn32_call_table)
PTR sys_timerfd_create
PTR compat_sys_timerfd_gettime /* 6285 */
PTR compat_sys_timerfd_settime
- PTR sys_signalfd4
+ PTR compat_sys_signalfd4
PTR sys_eventfd2
PTR sys_epoll_create1
PTR sys_dup3 /* 6290 */
PTR sys_pipe2
PTR sys_inotify_init1
- PTR sys_preadv
- PTR sys_pwritev
+ PTR compat_sys_preadv
+ PTR compat_sys_pwritev
PTR compat_sys_rt_tgsigqueueinfo /* 6295 */
PTR sys_perf_event_open
PTR sys_accept4
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index a53f8ec37aac..290dc6a1d7a3 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -79,7 +79,7 @@ static struct resource data_resource = { .name = "Kernel data", };
void __init add_memory_region(phys_t start, phys_t size, long type)
{
int x = boot_mem_map.nr_map;
- struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1;
+ int i;
/* Sanity check */
if (start + size < start) {
@@ -88,15 +88,29 @@ void __init add_memory_region(phys_t start, phys_t size, long type)
}
/*
- * Try to merge with previous entry if any. This is far less than
- * perfect but is sufficient for most real world cases.
+ * Try to merge with existing entry, if any.
*/
- if (x && prev->addr + prev->size == start && prev->type == type) {
- prev->size += size;
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ struct boot_mem_map_entry *entry = boot_mem_map.map + i;
+ unsigned long top;
+
+ if (entry->type != type)
+ continue;
+
+ if (start + size < entry->addr)
+ continue; /* no overlap */
+
+ if (entry->addr + entry->size < start)
+ continue; /* no overlap */
+
+ top = max(entry->addr + entry->size, start + size);
+ entry->addr = min(entry->addr, start);
+ entry->size = top - entry->addr;
+
return;
}
- if (x == BOOT_MEM_MAP_MAX) {
+ if (boot_mem_map.nr_map == BOOT_MEM_MAP_MAX) {
pr_err("Ooops! Too many entries in the memory map!\n");
return;
}
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index c4a82e841c73..eeddc58802e1 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -2,8 +2,9 @@
# Makefile for MIPS-specific library files..
#
-lib-y += csum_partial.o delay.o memcpy.o memset.o \
- strlen_user.o strncpy_user.o strnlen_user.o uncached.o
+lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
+ mips-atomic.o strlen_user.o strncpy_user.o \
+ strnlen_user.o uncached.o
obj-y += iomap.o
obj-$(CONFIG_PCI) += iomap-pci.o
diff --git a/arch/mips/lib/bitops.c b/arch/mips/lib/bitops.c
new file mode 100644
index 000000000000..239a9c957b02
--- /dev/null
+++ b/arch/mips/lib/bitops.c
@@ -0,0 +1,179 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1994-1997, 99, 2000, 06, 07 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (c) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/bitops.h>
+#include <linux/irqflags.h>
+#include <linux/export.h>
+
+
+/**
+ * __mips_set_bit - Atomically set a bit in memory. This is called by
+ * set_bit() if it cannot find a faster solution.
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ */
+void __mips_set_bit(unsigned long nr, volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ *a |= mask;
+ raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL(__mips_set_bit);
+
+
+/**
+ * __mips_clear_bit - Clears a bit in memory. This is called by clear_bit() if
+ * it cannot find a faster solution.
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ */
+void __mips_clear_bit(unsigned long nr, volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ *a &= ~mask;
+ raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL(__mips_clear_bit);
+
+
+/**
+ * __mips_change_bit - Toggle a bit in memory. This is called by change_bit()
+ * if it cannot find a faster solution.
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ */
+void __mips_change_bit(unsigned long nr, volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ *a ^= mask;
+ raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL(__mips_change_bit);
+
+
+/**
+ * __mips_test_and_set_bit - Set a bit and return its old value. This is
+ * called by test_and_set_bit() if it cannot find a faster solution.
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+int __mips_test_and_set_bit(unsigned long nr,
+ volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+ unsigned long res;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ res = (mask & *a);
+ *a |= mask;
+ raw_local_irq_restore(flags);
+ return res;
+}
+EXPORT_SYMBOL(__mips_test_and_set_bit);
+
+
+/**
+ * __mips_test_and_set_bit_lock - Set a bit and return its old value. This is
+ * called by test_and_set_bit_lock() if it cannot find a faster solution.
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+int __mips_test_and_set_bit_lock(unsigned long nr,
+ volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+ unsigned long res;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ res = (mask & *a);
+ *a |= mask;
+ raw_local_irq_restore(flags);
+ return res;
+}
+EXPORT_SYMBOL(__mips_test_and_set_bit_lock);
+
+
+/**
+ * __mips_test_and_clear_bit - Clear a bit and return its old value. This is
+ * called by test_and_clear_bit() if it cannot find a faster solution.
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ */
+int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+ unsigned long res;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ res = (mask & *a);
+ *a &= ~mask;
+ raw_local_irq_restore(flags);
+ return res;
+}
+EXPORT_SYMBOL(__mips_test_and_clear_bit);
+
+
+/**
+ * __mips_test_and_change_bit - Change a bit and return its old value. This is
+ * called by test_and_change_bit() if it cannot find a faster solution.
+ * @nr: Bit to change
+ * @addr: Address to count from
+ */
+int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
+{
+ volatile unsigned long *a = addr;
+ unsigned bit = nr & SZLONG_MASK;
+ unsigned long mask;
+ unsigned long flags;
+ unsigned long res;
+
+ a += nr >> SZLONG_LOG;
+ mask = 1UL << bit;
+ raw_local_irq_save(flags);
+ res = (mask & *a);
+ *a ^= mask;
+ raw_local_irq_restore(flags);
+ return res;
+}
+EXPORT_SYMBOL(__mips_test_and_change_bit);
diff --git a/arch/mips/lib/mips-atomic.c b/arch/mips/lib/mips-atomic.c
new file mode 100644
index 000000000000..cd160be3ce4d
--- /dev/null
+++ b/arch/mips/lib/mips-atomic.c
@@ -0,0 +1,176 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003 by Ralf Baechle
+ * Copyright (C) 1996 by Paul M. Antoine
+ * Copyright (C) 1999 Silicon Graphics
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ */
+#include <asm/irqflags.h>
+#include <asm/hazards.h>
+#include <linux/compiler.h>
+#include <linux/preempt.h>
+#include <linux/export.h>
+
+#if !defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT_SMTC)
+
+/*
+ * For cli() we have to insert nops to make sure that the new value
+ * has actually arrived in the status register before the end of this
+ * macro.
+ * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
+ * no nops at all.
+ */
+/*
+ * For TX49, operating only IE bit is not enough.
+ *
+ * If mfc0 $12 follows store and the mfc0 is last instruction of a
+ * page and fetching the next instruction causes TLB miss, the result
+ * of the mfc0 might wrongly contain EXL bit.
+ *
+ * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008
+ *
+ * Workaround: mask EXL bit of the result or place a nop before mfc0.
+ */
+__asm__(
+ " .macro arch_local_irq_disable\n"
+ " .set push \n"
+ " .set noat \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+ " mfc0 $1, $2, 1 \n"
+ " ori $1, 0x400 \n"
+ " .set noreorder \n"
+ " mtc0 $1, $2, 1 \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+ /* see irqflags.h for inline function */
+#else
+ " mfc0 $1,$12 \n"
+ " ori $1,0x1f \n"
+ " xori $1,0x1f \n"
+ " .set noreorder \n"
+ " mtc0 $1,$12 \n"
+#endif
+ " irq_disable_hazard \n"
+ " .set pop \n"
+ " .endm \n");
+
+notrace void arch_local_irq_disable(void)
+{
+ preempt_disable();
+ __asm__ __volatile__(
+ "arch_local_irq_disable"
+ : /* no outputs */
+ : /* no inputs */
+ : "memory");
+ preempt_enable();
+}
+EXPORT_SYMBOL(arch_local_irq_disable);
+
+
+__asm__(
+ " .macro arch_local_irq_save result \n"
+ " .set push \n"
+ " .set reorder \n"
+ " .set noat \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+ " mfc0 \\result, $2, 1 \n"
+ " ori $1, \\result, 0x400 \n"
+ " .set noreorder \n"
+ " mtc0 $1, $2, 1 \n"
+ " andi \\result, \\result, 0x400 \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+ /* see irqflags.h for inline function */
+#else
+ " mfc0 \\result, $12 \n"
+ " ori $1, \\result, 0x1f \n"
+ " xori $1, 0x1f \n"
+ " .set noreorder \n"
+ " mtc0 $1, $12 \n"
+#endif
+ " irq_disable_hazard \n"
+ " .set pop \n"
+ " .endm \n");
+
+notrace unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+ preempt_disable();
+ asm volatile("arch_local_irq_save\t%0"
+ : "=r" (flags)
+ : /* no inputs */
+ : "memory");
+ preempt_enable();
+ return flags;
+}
+EXPORT_SYMBOL(arch_local_irq_save);
+
+
+__asm__(
+ " .macro arch_local_irq_restore flags \n"
+ " .set push \n"
+ " .set noreorder \n"
+ " .set noat \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+ "mfc0 $1, $2, 1 \n"
+ "andi \\flags, 0x400 \n"
+ "ori $1, 0x400 \n"
+ "xori $1, 0x400 \n"
+ "or \\flags, $1 \n"
+ "mtc0 \\flags, $2, 1 \n"
+#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
+ /* see irqflags.h for inline function */
+#elif defined(CONFIG_CPU_MIPSR2)
+ /* see irqflags.h for inline function */
+#else
+ " mfc0 $1, $12 \n"
+ " andi \\flags, 1 \n"
+ " ori $1, 0x1f \n"
+ " xori $1, 0x1f \n"
+ " or \\flags, $1 \n"
+ " mtc0 \\flags, $12 \n"
+#endif
+ " irq_disable_hazard \n"
+ " .set pop \n"
+ " .endm \n");
+
+notrace void arch_local_irq_restore(unsigned long flags)
+{
+ unsigned long __tmp1;
+
+#ifdef CONFIG_MIPS_MT_SMTC
+ /*
+ * SMTC kernel needs to do a software replay of queued
+ * IPIs, at the cost of branch and call overhead on each
+ * local_irq_restore()
+ */
+ if (unlikely(!(flags & 0x0400)))
+ smtc_ipi_replay();
+#endif
+ preempt_disable();
+ __asm__ __volatile__(
+ "arch_local_irq_restore\t%0"
+ : "=r" (__tmp1)
+ : "0" (flags)
+ : "memory");
+ preempt_enable();
+}
+EXPORT_SYMBOL(arch_local_irq_restore);
+
+
+notrace void __arch_local_irq_restore(unsigned long flags)
+{
+ unsigned long __tmp1;
+
+ preempt_disable();
+ __asm__ __volatile__(
+ "arch_local_irq_restore\t%0"
+ : "=r" (__tmp1)
+ : "0" (flags)
+ : "memory");
+ preempt_enable();
+}
+EXPORT_SYMBOL(__arch_local_irq_restore);
+
+#endif /* !defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT_SMTC) */
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 4b9b935a070e..88e79ad6f811 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -120,18 +120,11 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
if (cpu_context(cpu, mm) != 0) {
unsigned long size, flags;
- int huge = is_vm_hugetlb_page(vma);
ENTER_CRITICAL(flags);
- if (huge) {
- start = round_down(start, HPAGE_SIZE);
- end = round_up(end, HPAGE_SIZE);
- size = (end - start) >> HPAGE_SHIFT;
- } else {
- start = round_down(start, PAGE_SIZE << 1);
- end = round_up(end, PAGE_SIZE << 1);
- size = (end - start) >> (PAGE_SHIFT + 1);
- }
+ start = round_down(start, PAGE_SIZE << 1);
+ end = round_up(end, PAGE_SIZE << 1);
+ size = (end - start) >> (PAGE_SHIFT + 1);
if (size <= current_cpu_data.tlbsize/2) {
int oldpid = read_c0_entryhi();
int newpid = cpu_asid(cpu, mm);
@@ -140,10 +133,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
int idx;
write_c0_entryhi(start | newpid);
- if (huge)
- start += HPAGE_SIZE;
- else
- start += (PAGE_SIZE << 1);
+ start += (PAGE_SIZE << 1);
mtc0_tlbw_hazard();
tlb_probe();
tlb_probe_hazard();
diff --git a/arch/mips/mti-malta/malta-platform.c b/arch/mips/mti-malta/malta-platform.c
index 80562b81f0f2..74732177851c 100644
--- a/arch/mips/mti-malta/malta-platform.c
+++ b/arch/mips/mti-malta/malta-platform.c
@@ -29,6 +29,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
+#include <asm/mips-boards/maltaint.h>
#include <mtd/mtd-abi.h>
#define SMC_PORT(base, int) \
@@ -48,7 +49,7 @@ static struct plat_serial8250_port uart8250_data[] = {
SMC_PORT(0x2F8, 3),
{
.mapbase = 0x1f000900, /* The CBUS UART */
- .irq = MIPS_CPU_IRQ_BASE + 2,
+ .irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2,
.uartclk = 3686400, /* Twice the usual clk! */
.iotype = UPIO_MEM32,
.flags = CBUS_UART_FLAGS,
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index 30110297f4f9..ddedc8a77861 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -84,7 +84,6 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe *frame = (struct rt_sigframe __user *)regs->sp;
sigset_t set;
- stack_t st;
/*
* Since we stacked the signal on a dword boundary,
@@ -104,11 +103,10 @@ asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
- goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->sp);
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+ goto badframe;
return regs->gpr[11];
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index fd49aeda9eb8..5dede04f2f3e 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -65,7 +65,8 @@ put_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
{
compat_sigset_t s;
- if (sz != sizeof *set) panic("put_sigset32()");
+ if (sz != sizeof *set)
+ return -EINVAL;
sigset_64to32(&s, set);
return copy_to_user(up, &s, sizeof s);
@@ -77,7 +78,8 @@ get_sigset32(compat_sigset_t __user *up, sigset_t *set, size_t sz)
compat_sigset_t s;
int r;
- if (sz != sizeof *set) panic("put_sigset32()");
+ if (sz != sizeof *set)
+ return -EINVAL;
if ((r = copy_from_user(&s, up, sz)) == 0) {
sigset_32to64(set, &s);
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 7426e40699bd..f76c10863c62 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -73,6 +73,8 @@ static unsigned long get_shared_area(struct address_space *mapping,
struct vm_area_struct *vma;
int offset = mapping ? get_offset(mapping) : 0;
+ offset = (offset + (pgoff << PAGE_SHIFT)) & 0x3FF000;
+
addr = DCACHE_ALIGN(addr - offset) + offset;
for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 3735abd7f8f6..cbf5d59d5d6a 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -60,7 +60,7 @@
ENTRY_SAME(fork_wrapper)
ENTRY_SAME(read)
ENTRY_SAME(write)
- ENTRY_SAME(open) /* 5 */
+ ENTRY_COMP(open) /* 5 */
ENTRY_SAME(close)
ENTRY_SAME(waitpid)
ENTRY_SAME(creat)
diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi
index 7ab286ab5300..39ed65a44c5f 100644
--- a/arch/powerpc/boot/dts/mpc5200b.dtsi
+++ b/arch/powerpc/boot/dts/mpc5200b.dtsi
@@ -231,6 +231,12 @@
interrupts = <2 7 0>;
};
+ sclpc@3c00 {
+ compatible = "fsl,mpc5200-lpbfifo";
+ reg = <0x3c00 0x60>;
+ interrupts = <2 23 0>;
+ };
+
i2c@3d00 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi
index 3444eb8f0ade..24f668039295 100644
--- a/arch/powerpc/boot/dts/o2d.dtsi
+++ b/arch/powerpc/boot/dts/o2d.dtsi
@@ -86,12 +86,6 @@
reg = <0>;
};
};
-
- sclpc@3c00 {
- compatible = "fsl,mpc5200-lpbfifo";
- reg = <0x3c00 0x60>;
- interrupts = <3 23 0>;
- };
};
localbus {
diff --git a/arch/powerpc/boot/dts/pcm030.dts b/arch/powerpc/boot/dts/pcm030.dts
index 9e354997eb7e..96512c058033 100644
--- a/arch/powerpc/boot/dts/pcm030.dts
+++ b/arch/powerpc/boot/dts/pcm030.dts
@@ -59,7 +59,7 @@
#gpio-cells = <2>;
};
- psc@2000 { /* PSC1 in ac97 mode */
+ audioplatform: psc@2000 { /* PSC1 in ac97 mode */
compatible = "mpc5200b-psc-ac97","fsl,mpc5200b-psc-ac97";
cell-index = <0>;
};
@@ -134,4 +134,9 @@
localbus {
status = "disabled";
};
+
+ sound {
+ compatible = "phytec,pcm030-audio-fabric";
+ asoc-platform = <&audioplatform>;
+ };
};
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index 8520b58a5e9a..b89ef65392dc 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -372,10 +372,11 @@ static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
- default:
- pr_err("%s: invalid irq: virq=%i, l1=%i, l2=%i\n",
- __func__, virq, l1irq, l2irq);
- return -EINVAL;
+ case MPC52xx_IRQ_L1_CRIT:
+ pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n",
+ __func__, l2irq);
+ irq_set_chip(virq, &no_irq_chip);
+ return 0;
}
irq_set_chip_and_handler(virq, irqchip, handle_level_irq);
diff --git a/arch/powerpc/platforms/pseries/eeh_pe.c b/arch/powerpc/platforms/pseries/eeh_pe.c
index 797cd181dc3f..d16c8ded1084 100644
--- a/arch/powerpc/platforms/pseries/eeh_pe.c
+++ b/arch/powerpc/platforms/pseries/eeh_pe.c
@@ -449,7 +449,7 @@ int eeh_rmv_from_parent_pe(struct eeh_dev *edev, int purge_pe)
if (list_empty(&pe->edevs)) {
cnt = 0;
list_for_each_entry(child, &pe->child_list, child) {
- if (!(pe->type & EEH_PE_INVALID)) {
+ if (!(child->type & EEH_PE_INVALID)) {
cnt++;
break;
}
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index d19f4977c834..e5b084723131 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -220,7 +220,8 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total)
/* Get the top level device in the PE */
edev = of_node_to_eeh_dev(dn);
- edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list);
+ if (edev->pe)
+ edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list);
dn = eeh_dev_to_of_node(edev);
if (!dn)
return NULL;
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 5dba755a43e6..d385f396dfee 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -96,6 +96,7 @@ config S390
select HAVE_MEMBLOCK_NODE_MAP
select HAVE_CMPXCHG_LOCAL
select HAVE_CMPXCHG_DOUBLE
+ select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select HAVE_VIRT_CPU_ACCOUNTING
select VIRT_CPU_ACCOUNTING
select ARCH_DISCARD_MEMBLOCK
diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
index a34a9d612fc0..18cd6b592650 100644
--- a/arch/s390/include/asm/compat.h
+++ b/arch/s390/include/asm/compat.h
@@ -20,7 +20,7 @@
#define PSW32_MASK_CC 0x00003000UL
#define PSW32_MASK_PM 0x00000f00UL
-#define PSW32_MASK_USER 0x00003F00UL
+#define PSW32_MASK_USER 0x0000FF00UL
#define PSW32_ADDR_AMODE 0x80000000UL
#define PSW32_ADDR_INSN 0x7FFFFFFFUL
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index 9ca305383760..9935cbd6a46f 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -8,6 +8,9 @@ struct cpu;
#ifdef CONFIG_SCHED_BOOK
+extern unsigned char cpu_socket_id[NR_CPUS];
+#define topology_physical_package_id(cpu) (cpu_socket_id[cpu])
+
extern unsigned char cpu_core_id[NR_CPUS];
extern cpumask_t cpu_core_map[NR_CPUS];
diff --git a/arch/s390/include/uapi/asm/ptrace.h b/arch/s390/include/uapi/asm/ptrace.h
index 705588a16d70..a5ca214b34fd 100644
--- a/arch/s390/include/uapi/asm/ptrace.h
+++ b/arch/s390/include/uapi/asm/ptrace.h
@@ -239,7 +239,7 @@ typedef struct
#define PSW_MASK_EA 0x00000000UL
#define PSW_MASK_BA 0x00000000UL
-#define PSW_MASK_USER 0x00003F00UL
+#define PSW_MASK_USER 0x0000FF00UL
#define PSW_ADDR_AMODE 0x80000000UL
#define PSW_ADDR_INSN 0x7FFFFFFFUL
@@ -269,7 +269,7 @@ typedef struct
#define PSW_MASK_EA 0x0000000100000000UL
#define PSW_MASK_BA 0x0000000080000000UL
-#define PSW_MASK_USER 0x00003F8180000000UL
+#define PSW_MASK_USER 0x0000FF8180000000UL
#define PSW_ADDR_AMODE 0x0000000000000000UL
#define PSW_ADDR_INSN 0xFFFFFFFFFFFFFFFFUL
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index a1e8a8694bb7..593fcc9253fc 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -309,6 +309,10 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
(__u64)(regs32.psw.mask & PSW32_MASK_USER) << 32 |
(__u64)(regs32.psw.addr & PSW32_ADDR_AMODE);
+ /* Check for invalid user address space control. */
+ if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
+ regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
+ (regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN);
for (i = 0; i < NUM_GPRS; i++)
regs->gprs[i] = (__u64) regs32.gprs[i];
@@ -481,7 +485,10 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
/* Set up registers for signal handler */
regs->gprs[15] = (__force __u64) frame;
- regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
+ /* Force 31 bit amode and default user address space control. */
+ regs->psw.mask = PSW_MASK_BA |
+ (psw_user_bits & PSW_MASK_ASC) |
+ (regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (__force __u64) ka->sa.sa_handler;
regs->gprs[2] = map_signal(sig);
@@ -549,7 +556,10 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up registers for signal handler */
regs->gprs[15] = (__force __u64) frame;
- regs->psw.mask |= PSW_MASK_BA; /* force amode 31 */
+ /* Force 31 bit amode and default user address space control. */
+ regs->psw.mask = PSW_MASK_BA |
+ (psw_user_bits & PSW_MASK_ASC) |
+ (regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (__u64) ka->sa.sa_handler;
regs->gprs[2] = map_signal(sig);
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index ad79b846535c..827e094a2f49 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -28,7 +28,7 @@ ENTRY(sys32_open_wrapper)
llgtr %r2,%r2 # const char *
lgfr %r3,%r3 # int
lgfr %r4,%r4 # int
- jg sys_open # branch to system call
+ jg compat_sys_open # branch to system call
ENTRY(sys32_close_wrapper)
llgfr %r2,%r2 # unsigned int
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index c13a2a37ef00..d1259d875074 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -136,6 +136,10 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
/* Use regs->psw.mask instead of psw_user_bits to preserve PER bit. */
regs->psw.mask = (regs->psw.mask & ~PSW_MASK_USER) |
(user_sregs.regs.psw.mask & PSW_MASK_USER);
+ /* Check for invalid user address space control. */
+ if ((regs->psw.mask & PSW_MASK_ASC) >= (psw_kernel_bits & PSW_MASK_ASC))
+ regs->psw.mask = (psw_user_bits & PSW_MASK_ASC) |
+ (regs->psw.mask & ~PSW_MASK_ASC);
/* Check for invalid amode */
if (regs->psw.mask & PSW_MASK_EA)
regs->psw.mask |= PSW_MASK_BA;
@@ -273,7 +277,10 @@ static int setup_frame(int sig, struct k_sigaction *ka,
/* Set up registers for signal handler */
regs->gprs[15] = (unsigned long) frame;
- regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
+ /* Force default amode and default user address space control. */
+ regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
+ (psw_user_bits & PSW_MASK_ASC) |
+ (regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
regs->gprs[2] = map_signal(sig);
@@ -346,7 +353,10 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up registers for signal handler */
regs->gprs[15] = (unsigned long) frame;
- regs->psw.mask |= PSW_MASK_EA | PSW_MASK_BA; /* 64 bit amode */
+ /* Force default amode and default user address space control. */
+ regs->psw.mask = PSW_MASK_EA | PSW_MASK_BA |
+ (psw_user_bits & PSW_MASK_ASC) |
+ (regs->psw.mask & ~PSW_MASK_ASC);
regs->psw.addr = (unsigned long) ka->sa.sa_handler | PSW_ADDR_AMODE;
regs->gprs[2] = map_signal(sig);
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 54d93f4b6818..dd55f7c20104 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -40,6 +40,7 @@ static DEFINE_SPINLOCK(topology_lock);
static struct mask_info core_info;
cpumask_t cpu_core_map[NR_CPUS];
unsigned char cpu_core_id[NR_CPUS];
+unsigned char cpu_socket_id[NR_CPUS];
static struct mask_info book_info;
cpumask_t cpu_book_map[NR_CPUS];
@@ -83,11 +84,12 @@ static struct mask_info *add_cpus_to_mask(struct topology_cpu *tl_cpu,
cpumask_set_cpu(lcpu, &book->mask);
cpu_book_id[lcpu] = book->id;
cpumask_set_cpu(lcpu, &core->mask);
+ cpu_core_id[lcpu] = rcpu;
if (one_core_per_cpu) {
- cpu_core_id[lcpu] = rcpu;
+ cpu_socket_id[lcpu] = rcpu;
core = core->next;
} else {
- cpu_core_id[lcpu] = core->id;
+ cpu_socket_id[lcpu] = core->id;
}
smp_cpu_set_polarization(lcpu, tl_cpu->pp);
}
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index 8b8285310b5a..1f5315d1215c 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -180,8 +180,7 @@ int __get_user_pages_fast(unsigned long start, int nr_pages, int write,
addr = start;
len = (unsigned long) nr_pages << PAGE_SHIFT;
end = start + len;
- if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
- (void __user *)start, len)))
+ if ((end < start) || (end > TASK_SIZE))
return 0;
local_irq_save(flags);
@@ -229,7 +228,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
addr = start;
len = (unsigned long) nr_pages << PAGE_SHIFT;
end = start + len;
- if (end < start)
+ if ((end < start) || (end > TASK_SIZE))
goto slow_irqon;
/*
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index c268bbf8b410..02353bde92d8 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -148,7 +148,6 @@ score_rt_sigreturn(struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
sigset_t set;
- stack_t st;
int sig;
/* Always make any pending restarted system calls return -EINTR */
@@ -168,12 +167,10 @@ score_rt_sigreturn(struct pt_regs *regs)
else if (sig)
force_sig(sig, current);
- if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st)))
- goto badframe;
-
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack((stack_t __user *)&st, NULL, regs->regs[0]);
+ if (do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs->regs[0]) == -EFAULT)
+ goto badframe;
regs->is_syscall = 0;
__asm__ __volatile__(
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 23853814bd17..d867cd95a622 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -347,7 +347,6 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
{
struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (long) REF_REG_SP;
sigset_t set;
- stack_t __user st;
long long ret;
/* Always make any pending restarted system calls return -EINTR */
@@ -365,11 +364,10 @@ asmlinkage int sys_rt_sigreturn(unsigned long r2, unsigned long r3,
goto badframe;
regs->pc -= 4;
- if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
- goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, REF_REG_SP);
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, REF_REG_SP) == -EFAULT)
+ goto badframe;
return (int) ret;
diff --git a/arch/sparc/boot/piggyback.c b/arch/sparc/boot/piggyback.c
index c0a798fcf030..bb7c95161d71 100644
--- a/arch/sparc/boot/piggyback.c
+++ b/arch/sparc/boot/piggyback.c
@@ -81,18 +81,18 @@ static void usage(void)
static int start_line(const char *line)
{
- if (strcmp(line + 8, " T _start\n") == 0)
+ if (strcmp(line + 10, " _start\n") == 0)
return 1;
- else if (strcmp(line + 16, " T _start\n") == 0)
+ else if (strcmp(line + 18, " _start\n") == 0)
return 1;
return 0;
}
static int end_line(const char *line)
{
- if (strcmp(line + 8, " A _end\n") == 0)
+ if (strcmp(line + 10, " _end\n") == 0)
return 1;
- else if (strcmp (line + 16, " A _end\n") == 0)
+ else if (strcmp (line + 18, " _end\n") == 0)
return 1;
return 0;
}
@@ -100,8 +100,8 @@ static int end_line(const char *line)
/*
* Find address for start and end in System.map.
* The file looks like this:
- * f0004000 T _start
- * f0379f79 A _end
+ * f0004000 ... _start
+ * f0379f79 ... _end
* 1234567890123456
* ^coloumn 1
* There is support for 64 bit addresses too.
diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
index f93003123bce..67c62578d170 100644
--- a/arch/sparc/include/asm/prom.h
+++ b/arch/sparc/include/asm/prom.h
@@ -63,10 +63,13 @@ extern char *of_console_options;
extern void irq_trans_init(struct device_node *dp);
extern char *build_path_component(struct device_node *dp);
-/* SPARC has a local implementation */
+/* SPARC has local implementations */
extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
#define of_address_to_resource of_address_to_resource
+void __iomem *of_iomap(struct device_node *node, int index);
+#define of_iomap of_iomap
+
#endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 867de2f8189c..689e1ba62809 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -295,9 +295,7 @@ void do_rt_sigreturn(struct pt_regs *regs)
err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
- err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
-
- if (err)
+ if (err || do_sigaltstack(&sf->stack, NULL, (unsigned long)sf) == -EFAULT)
goto segv;
err |= __get_user(rwin_save, &sf->rwin_save);
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
index 44025f4ba41f..8475a474273a 100644
--- a/arch/sparc/kernel/sys32.S
+++ b/arch/sparc/kernel/sys32.S
@@ -47,7 +47,7 @@ STUB: sra REG1, 0, REG1; \
sra REG4, 0, REG4
SIGN1(sys32_exit, sparc_exit, %o0)
-SIGN1(sys32_exit_group, sys_exit_group, %o0)
+SIGN1(sys32_exit_group, sparc_exit_group, %o0)
SIGN1(sys32_wait4, compat_sys_wait4, %o2)
SIGN1(sys32_creat, sys_creat, %o1)
SIGN1(sys32_mknod, sys_mknod, %o1)
diff --git a/arch/sparc/kernel/syscalls.S b/arch/sparc/kernel/syscalls.S
index 7f5f65d0b3fd..bf2347794e33 100644
--- a/arch/sparc/kernel/syscalls.S
+++ b/arch/sparc/kernel/syscalls.S
@@ -118,10 +118,20 @@ ret_from_syscall:
ba,pt %xcc, ret_sys_call
ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
+ .globl sparc_exit_group
+ .type sparc_exit_group,#function
+sparc_exit_group:
+ sethi %hi(sys_exit_group), %g7
+ ba,pt %xcc, 1f
+ or %g7, %lo(sys_exit_group), %g7
+ .size sparc_exit_group,.-sparc_exit_group
+
.globl sparc_exit
.type sparc_exit,#function
sparc_exit:
- rdpr %pstate, %g2
+ sethi %hi(sys_exit), %g7
+ or %g7, %lo(sys_exit), %g7
+1: rdpr %pstate, %g2
wrpr %g2, PSTATE_IE, %pstate
rdpr %otherwin, %g1
rdpr %cansave, %g3
@@ -129,7 +139,7 @@ sparc_exit:
wrpr %g3, 0x0, %cansave
wrpr %g0, 0x0, %otherwin
wrpr %g2, 0x0, %pstate
- ba,pt %xcc, sys_exit
+ jmpl %g7, %g0
stb %g0, [%g6 + TI_WSAVED]
.size sparc_exit,.-sparc_exit
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index 1c9af9fa38e9..017b74a63dcb 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -133,7 +133,7 @@ sys_call_table:
/*170*/ .word sys_lsetxattr, sys_fsetxattr, sys_getxattr, sys_lgetxattr, sys_getdents
.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
/*180*/ .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_ni_syscall
- .word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
+ .word sys_setpgid, sys_fremovexattr, sys_tkill, sparc_exit_group, sys_newuname
/*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, sys_nis_syscall, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 3a8ece7d09ca..0d7103c9eff3 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -32,13 +32,14 @@ void flush_thread(void)
"err = %d\n", ret);
force_sig(SIGKILL, current);
}
+ get_safe_registers(current_pt_regs()->regs.gp,
+ current_pt_regs()->regs.fp);
__switch_mm(&current->mm->context.id);
}
void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
{
- get_safe_registers(regs->regs.gp, regs->regs.fp);
PT_REGS_IP(regs) = eip;
PT_REGS_SP(regs) = esp;
current->ptrace &= ~PT_DTRACE;
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index e5c5473e69ce..c4fbb21e802b 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -16,6 +16,8 @@ config UNICORE32
select ARCH_WANT_FRAME_POINTERS
select GENERIC_IOMAP
select MODULES_USE_ELF_REL
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
help
UniCore-32 is 32-bit Instruction Set Architecture,
including a series of low-power-consumption RISC chip
@@ -64,6 +66,9 @@ config GENERIC_CALIBRATE_DELAY
config ARCH_MAY_HAVE_PC_FDC
bool
+config ZONE_DMA
+ def_bool y
+
config NEED_DMA_MAP_STATE
def_bool y
@@ -216,7 +221,7 @@ config PUV3_GPIO
bool
depends on !ARCH_FPGA
select GENERIC_GPIO
- select GPIO_SYSFS if EXPERIMENTAL
+ select GPIO_SYSFS
default y
if PUV3_NB0916
diff --git a/arch/unicore32/include/asm/Kbuild b/arch/unicore32/include/asm/Kbuild
index c910c9857e11..601e92f18af6 100644
--- a/arch/unicore32/include/asm/Kbuild
+++ b/arch/unicore32/include/asm/Kbuild
@@ -1,4 +1,3 @@
-include include/asm-generic/Kbuild.asm
generic-y += atomic.h
generic-y += auxvec.h
diff --git a/arch/unicore32/include/asm/bug.h b/arch/unicore32/include/asm/bug.h
index b1ff8cadb086..93a56f3e2344 100644
--- a/arch/unicore32/include/asm/bug.h
+++ b/arch/unicore32/include/asm/bug.h
@@ -19,9 +19,4 @@ extern void die(const char *msg, struct pt_regs *regs, int err);
extern void uc32_notify_die(const char *str, struct pt_regs *regs,
struct siginfo *info, unsigned long err, unsigned long trap);
-extern asmlinkage void __backtrace(void);
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
-
-extern void __show_regs(struct pt_regs *);
-
#endif /* __UNICORE_BUG_H__ */
diff --git a/arch/unicore32/include/asm/cmpxchg.h b/arch/unicore32/include/asm/cmpxchg.h
index df4d5acfd19f..8e797ad4fa24 100644
--- a/arch/unicore32/include/asm/cmpxchg.h
+++ b/arch/unicore32/include/asm/cmpxchg.h
@@ -35,7 +35,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
: "memory", "cc");
break;
default:
- ret = __xchg_bad_pointer();
+ __xchg_bad_pointer();
}
return ret;
diff --git a/arch/unicore32/include/asm/kvm_para.h b/arch/unicore32/include/asm/kvm_para.h
deleted file mode 100644
index 14fab8f0b957..000000000000
--- a/arch/unicore32/include/asm/kvm_para.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
diff --git a/arch/unicore32/include/asm/processor.h b/arch/unicore32/include/asm/processor.h
index 14382cb09657..4eaa42167667 100644
--- a/arch/unicore32/include/asm/processor.h
+++ b/arch/unicore32/include/asm/processor.h
@@ -72,11 +72,6 @@ unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
-/*
- * Create a new kernel thread
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
#define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
diff --git a/arch/unicore32/include/asm/ptrace.h b/arch/unicore32/include/asm/ptrace.h
index b9caf9b0997b..726749dab52f 100644
--- a/arch/unicore32/include/asm/ptrace.h
+++ b/arch/unicore32/include/asm/ptrace.h
@@ -12,80 +12,10 @@
#ifndef __UNICORE_PTRACE_H__
#define __UNICORE_PTRACE_H__
-#define PTRACE_GET_THREAD_AREA 22
-
-/*
- * PSR bits
- */
-#define USER_MODE 0x00000010
-#define REAL_MODE 0x00000011
-#define INTR_MODE 0x00000012
-#define PRIV_MODE 0x00000013
-#define ABRT_MODE 0x00000017
-#define EXTN_MODE 0x0000001b
-#define SUSR_MODE 0x0000001f
-#define MODE_MASK 0x0000001f
-#define PSR_R_BIT 0x00000040
-#define PSR_I_BIT 0x00000080
-#define PSR_V_BIT 0x10000000
-#define PSR_C_BIT 0x20000000
-#define PSR_Z_BIT 0x40000000
-#define PSR_S_BIT 0x80000000
-
-/*
- * Groups of PSR bits
- */
-#define PSR_f 0xff000000 /* Flags */
-#define PSR_c 0x000000ff /* Control */
+#include <uapi/asm/ptrace.h>
#ifndef __ASSEMBLY__
-/*
- * This struct defines the way the registers are stored on the
- * stack during a system call. Note that sizeof(struct pt_regs)
- * has to be a multiple of 8.
- */
-struct pt_regs {
- unsigned long uregs[34];
-};
-
-#define UCreg_asr uregs[32]
-#define UCreg_pc uregs[31]
-#define UCreg_lr uregs[30]
-#define UCreg_sp uregs[29]
-#define UCreg_ip uregs[28]
-#define UCreg_fp uregs[27]
-#define UCreg_26 uregs[26]
-#define UCreg_25 uregs[25]
-#define UCreg_24 uregs[24]
-#define UCreg_23 uregs[23]
-#define UCreg_22 uregs[22]
-#define UCreg_21 uregs[21]
-#define UCreg_20 uregs[20]
-#define UCreg_19 uregs[19]
-#define UCreg_18 uregs[18]
-#define UCreg_17 uregs[17]
-#define UCreg_16 uregs[16]
-#define UCreg_15 uregs[15]
-#define UCreg_14 uregs[14]
-#define UCreg_13 uregs[13]
-#define UCreg_12 uregs[12]
-#define UCreg_11 uregs[11]
-#define UCreg_10 uregs[10]
-#define UCreg_09 uregs[9]
-#define UCreg_08 uregs[8]
-#define UCreg_07 uregs[7]
-#define UCreg_06 uregs[6]
-#define UCreg_05 uregs[5]
-#define UCreg_04 uregs[4]
-#define UCreg_03 uregs[3]
-#define UCreg_02 uregs[2]
-#define UCreg_01 uregs[1]
-#define UCreg_00 uregs[0]
-#define UCreg_ORIG_00 uregs[33]
-
-#ifdef __KERNEL__
-
#define user_mode(regs) \
(processor_mode(regs) == USER_MODE)
@@ -125,9 +55,5 @@ static inline int valid_user_regs(struct pt_regs *regs)
#define instruction_pointer(regs) ((regs)->UCreg_pc)
-#endif /* __KERNEL__ */
-
#endif /* __ASSEMBLY__ */
-
#endif
-
diff --git a/arch/unicore32/include/uapi/asm/Kbuild b/arch/unicore32/include/uapi/asm/Kbuild
index baebb3da1d44..0514d7ad6855 100644
--- a/arch/unicore32/include/uapi/asm/Kbuild
+++ b/arch/unicore32/include/uapi/asm/Kbuild
@@ -1,3 +1,10 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
+header-y += byteorder.h
+header-y += kvm_para.h
+header-y += ptrace.h
+header-y += sigcontext.h
+header-y += unistd.h
+
+generic-y += kvm_para.h
diff --git a/arch/unicore32/include/asm/byteorder.h b/arch/unicore32/include/uapi/asm/byteorder.h
index ebe1b3fef3e3..ebe1b3fef3e3 100644
--- a/arch/unicore32/include/asm/byteorder.h
+++ b/arch/unicore32/include/uapi/asm/byteorder.h
diff --git a/arch/unicore32/include/uapi/asm/ptrace.h b/arch/unicore32/include/uapi/asm/ptrace.h
new file mode 100644
index 000000000000..187aa2e98a53
--- /dev/null
+++ b/arch/unicore32/include/uapi/asm/ptrace.h
@@ -0,0 +1,90 @@
+/*
+ * linux/arch/unicore32/include/asm/ptrace.h
+ *
+ * Code specific to PKUnity SoC and UniCore ISA
+ *
+ * Copyright (C) 2001-2010 GUAN Xue-tao
+ *
+ * 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__UNICORE_PTRACE_H__
+#define _UAPI__UNICORE_PTRACE_H__
+
+#define PTRACE_GET_THREAD_AREA 22
+
+/*
+ * PSR bits
+ */
+#define USER_MODE 0x00000010
+#define REAL_MODE 0x00000011
+#define INTR_MODE 0x00000012
+#define PRIV_MODE 0x00000013
+#define ABRT_MODE 0x00000017
+#define EXTN_MODE 0x0000001b
+#define SUSR_MODE 0x0000001f
+#define MODE_MASK 0x0000001f
+#define PSR_R_BIT 0x00000040
+#define PSR_I_BIT 0x00000080
+#define PSR_V_BIT 0x10000000
+#define PSR_C_BIT 0x20000000
+#define PSR_Z_BIT 0x40000000
+#define PSR_S_BIT 0x80000000
+
+/*
+ * Groups of PSR bits
+ */
+#define PSR_f 0xff000000 /* Flags */
+#define PSR_c 0x000000ff /* Control */
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This struct defines the way the registers are stored on the
+ * stack during a system call. Note that sizeof(struct pt_regs)
+ * has to be a multiple of 8.
+ */
+struct pt_regs {
+ unsigned long uregs[34];
+};
+
+#define UCreg_asr uregs[32]
+#define UCreg_pc uregs[31]
+#define UCreg_lr uregs[30]
+#define UCreg_sp uregs[29]
+#define UCreg_ip uregs[28]
+#define UCreg_fp uregs[27]
+#define UCreg_26 uregs[26]
+#define UCreg_25 uregs[25]
+#define UCreg_24 uregs[24]
+#define UCreg_23 uregs[23]
+#define UCreg_22 uregs[22]
+#define UCreg_21 uregs[21]
+#define UCreg_20 uregs[20]
+#define UCreg_19 uregs[19]
+#define UCreg_18 uregs[18]
+#define UCreg_17 uregs[17]
+#define UCreg_16 uregs[16]
+#define UCreg_15 uregs[15]
+#define UCreg_14 uregs[14]
+#define UCreg_13 uregs[13]
+#define UCreg_12 uregs[12]
+#define UCreg_11 uregs[11]
+#define UCreg_10 uregs[10]
+#define UCreg_09 uregs[9]
+#define UCreg_08 uregs[8]
+#define UCreg_07 uregs[7]
+#define UCreg_06 uregs[6]
+#define UCreg_05 uregs[5]
+#define UCreg_04 uregs[4]
+#define UCreg_03 uregs[3]
+#define UCreg_02 uregs[2]
+#define UCreg_01 uregs[1]
+#define UCreg_00 uregs[0]
+#define UCreg_ORIG_00 uregs[33]
+
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _UAPI__UNICORE_PTRACE_H__ */
diff --git a/arch/unicore32/include/asm/sigcontext.h b/arch/unicore32/include/uapi/asm/sigcontext.h
index 6a2d7671c052..6a2d7671c052 100644
--- a/arch/unicore32/include/asm/sigcontext.h
+++ b/arch/unicore32/include/uapi/asm/sigcontext.h
diff --git a/arch/unicore32/include/asm/unistd.h b/arch/unicore32/include/uapi/asm/unistd.h
index 2abcf61c615d..d18a3be89b38 100644
--- a/arch/unicore32/include/asm/unistd.h
+++ b/arch/unicore32/include/uapi/asm/unistd.h
@@ -12,3 +12,4 @@
/* Use the standard ABI for syscalls. */
#include <asm-generic/unistd.h>
+#define __ARCH_WANT_SYS_EXECVE
diff --git a/arch/unicore32/kernel/entry.S b/arch/unicore32/kernel/entry.S
index dcb87ab19ddd..7049350c790f 100644
--- a/arch/unicore32/kernel/entry.S
+++ b/arch/unicore32/kernel/entry.S
@@ -573,17 +573,16 @@ ENDPROC(ret_to_user)
*/
ENTRY(ret_from_fork)
b.l schedule_tail
- get_thread_info tsk
- ldw r1, [tsk+], #TI_FLAGS @ check for syscall tracing
- mov why, #1
- cand.a r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
- beq ret_slow_syscall
- mov r1, sp
- mov r0, #1 @ trace exit [IP = 1]
- b.l syscall_trace
b ret_slow_syscall
ENDPROC(ret_from_fork)
+ENTRY(ret_from_kernel_thread)
+ b.l schedule_tail
+ mov r0, r5
+ adr lr, ret_slow_syscall
+ mov pc, r4
+ENDPROC(ret_from_kernel_thread)
+
/*=============================================================================
* SWI handler
*-----------------------------------------------------------------------------
@@ -669,11 +668,6 @@ __cr_alignment:
#endif
.ltorg
-ENTRY(sys_execve)
- add r3, sp, #S_OFF
- b __sys_execve
-ENDPROC(sys_execve)
-
ENTRY(sys_clone)
add ip, sp, #S_OFF
stw ip, [sp+], #4
diff --git a/arch/unicore32/kernel/process.c b/arch/unicore32/kernel/process.c
index b008586dad75..a8fe265ce2c0 100644
--- a/arch/unicore32/kernel/process.c
+++ b/arch/unicore32/kernel/process.c
@@ -258,6 +258,7 @@ void release_thread(struct task_struct *dead_task)
}
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+asmlinkage void ret_from_kernel_thread(void) __asm__("ret_from_kernel_thread");
int
copy_thread(unsigned long clone_flags, unsigned long stack_start,
@@ -266,17 +267,22 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
struct thread_info *thread = task_thread_info(p);
struct pt_regs *childregs = task_pt_regs(p);
- *childregs = *regs;
- childregs->UCreg_00 = 0;
- childregs->UCreg_sp = stack_start;
-
memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
thread->cpu_context.sp = (unsigned long)childregs;
- thread->cpu_context.pc = (unsigned long)ret_from_fork;
-
- if (clone_flags & CLONE_SETTLS)
- childregs->UCreg_16 = regs->UCreg_03;
+ if (unlikely(!regs)) {
+ thread->cpu_context.pc = (unsigned long)ret_from_kernel_thread;
+ thread->cpu_context.r4 = stack_start;
+ thread->cpu_context.r5 = stk_sz;
+ memset(childregs, 0, sizeof(struct pt_regs));
+ } else {
+ thread->cpu_context.pc = (unsigned long)ret_from_fork;
+ *childregs = *regs;
+ childregs->UCreg_00 = 0;
+ childregs->UCreg_sp = stack_start;
+ if (clone_flags & CLONE_SETTLS)
+ childregs->UCreg_16 = regs->UCreg_03;
+ }
return 0;
}
@@ -305,42 +311,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fp)
}
EXPORT_SYMBOL(dump_fpu);
-/*
- * Shuffle the argument into the correct register before calling the
- * thread function. r1 is the thread argument, r2 is the pointer to
- * the thread function, and r3 points to the exit function.
- */
-asm(".pushsection .text\n"
-" .align\n"
-" .type kernel_thread_helper, #function\n"
-"kernel_thread_helper:\n"
-" mov.a asr, r7\n"
-" mov r0, r4\n"
-" mov lr, r6\n"
-" mov pc, r5\n"
-" .size kernel_thread_helper, . - kernel_thread_helper\n"
-" .popsection");
-
-/*
- * Create a kernel thread.
- */
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.UCreg_04 = (unsigned long)arg;
- regs.UCreg_05 = (unsigned long)fn;
- regs.UCreg_06 = (unsigned long)do_exit;
- regs.UCreg_07 = PRIV_MODE;
- regs.UCreg_pc = (unsigned long)kernel_thread_helper;
- regs.UCreg_asr = regs.UCreg_07 | PSR_I_BIT;
-
- return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
unsigned long get_wchan(struct task_struct *p)
{
struct stackframe frame;
diff --git a/arch/unicore32/kernel/setup.h b/arch/unicore32/kernel/setup.h
index f23955028a18..30f749da8f73 100644
--- a/arch/unicore32/kernel/setup.h
+++ b/arch/unicore32/kernel/setup.h
@@ -30,4 +30,10 @@ extern char __vectors_start[], __vectors_end[];
extern void kernel_thread_helper(void);
extern void __init early_signal_init(void);
+
+extern asmlinkage void __backtrace(void);
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+
+extern void __show_regs(struct pt_regs *);
+
#endif
diff --git a/arch/unicore32/kernel/sys.c b/arch/unicore32/kernel/sys.c
index fabdee96110b..9680134b31f0 100644
--- a/arch/unicore32/kernel/sys.c
+++ b/arch/unicore32/kernel/sys.c
@@ -42,69 +42,6 @@ asmlinkage long __sys_clone(unsigned long clone_flags, unsigned long newsp,
parent_tid, child_tid);
}
-/* sys_execve() executes a new program.
- * This is called indirectly via a small wrapper
- */
-asmlinkage long __sys_execve(const char __user *filename,
- const char __user *const __user *argv,
- const char __user *const __user *envp,
- struct pt_regs *regs)
-{
- int error;
- struct filename *fn;
-
- fn = getname(filename);
- error = PTR_ERR(fn);
- if (IS_ERR(fn))
- goto out;
- error = do_execve(fn->name, argv, envp, regs);
- putname(fn);
-out:
- return error;
-}
-
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- struct pt_regs regs;
- int ret;
-
- memset(&regs, 0, sizeof(struct pt_regs));
- ret = do_execve(filename,
- (const char __user *const __user *)argv,
- (const char __user *const __user *)envp, &regs);
- if (ret < 0)
- goto out;
-
- /*
- * Save argc to the register structure for userspace.
- */
- regs.UCreg_00 = ret;
-
- /*
- * We were successful. We won't be returning to our caller, but
- * instead to user space by manipulating the kernel stack.
- */
- asm("add r0, %0, %1\n\t"
- "mov r1, %2\n\t"
- "mov r2, %3\n\t"
- "mov r22, #0\n\t" /* not a syscall */
- "mov r23, %0\n\t" /* thread structure */
- "b.l memmove\n\t" /* copy regs to top of stack */
- "mov sp, r0\n\t" /* reposition stack pointer */
- "b ret_to_user"
- :
- : "r" (current_thread_info()),
- "Ir" (THREAD_START_SP - sizeof(regs)),
- "r" (&regs),
- "Ir" (sizeof(regs))
- : "r0", "r1", "r2", "r3", "ip", "lr", "memory");
-
- out:
- return ret;
-}
-
/* Note: used by the compat code even in 64-bit Linux. */
SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags,
diff --git a/arch/unicore32/mm/fault.c b/arch/unicore32/mm/fault.c
index 2eeb9c04cab0..f9b5c10bccee 100644
--- a/arch/unicore32/mm/fault.c
+++ b/arch/unicore32/mm/fault.c
@@ -168,7 +168,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
}
static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
- struct task_struct *tsk)
+ unsigned int flags, struct task_struct *tsk)
{
struct vm_area_struct *vma;
int fault;
@@ -194,14 +194,7 @@ good_area:
* If for any reason at all we couldn't handle the fault, make
* sure we exit gracefully rather than endlessly redo the fault.
*/
- fault = handle_mm_fault(mm, vma, addr & PAGE_MASK,
- (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR))
- return fault;
- if (fault & VM_FAULT_MAJOR)
- tsk->maj_flt++;
- else
- tsk->min_flt++;
+ fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
return fault;
check_stack:
@@ -216,6 +209,8 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
struct task_struct *tsk;
struct mm_struct *mm;
int fault, sig, code;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+ ((!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
tsk = current;
mm = tsk->mm;
@@ -236,6 +231,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (!user_mode(regs)
&& !search_exception_tables(regs->UCreg_pc))
goto no_context;
+retry:
down_read(&mm->mmap_sem);
} else {
/*
@@ -251,7 +247,28 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
#endif
}
- fault = __do_pf(mm, addr, fsr, tsk);
+ fault = __do_pf(mm, addr, fsr, flags, tsk);
+
+ /* If we need to retry but a fatal signal is pending, handle the
+ * signal first. We do not need to release the mmap_sem because
+ * it would already be released in __lock_page_or_retry in
+ * mm/filemap.c. */
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ return 0;
+
+ if (!(fault & VM_FAULT_ERROR) && (flags & FAULT_FLAG_ALLOW_RETRY)) {
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+ if (fault & VM_FAULT_RETRY) {
+ /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+ * of starvation. */
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ goto retry;
+ }
+ }
+
up_read(&mm->mmap_sem);
/*
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index c760e073963e..e87b0cac14b5 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -12,6 +12,8 @@
#include <asm/setup.h>
#include <asm/desc.h>
+#undef memcpy /* Use memcpy from misc.c */
+
#include "eboot.h"
static efi_system_table_t *sys_table;
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 2a017441b8b2..8c132a625b94 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -476,6 +476,3 @@ die:
setup_corrupt:
.byte 7
.string "No setup signature found...\n"
-
- .data
-dummy: .long 0
diff --git a/arch/x86/include/asm/Kbuild b/arch/x86/include/asm/Kbuild
index 66e5f0ef0523..79fd8a3418f9 100644
--- a/arch/x86/include/asm/Kbuild
+++ b/arch/x86/include/asm/Kbuild
@@ -12,6 +12,7 @@ header-y += mce.h
header-y += msr-index.h
header-y += msr.h
header-y += mtrr.h
+header-y += perf_regs.h
header-y += posix_types_32.h
header-y += posix_types_64.h
header-y += posix_types_x32.h
@@ -19,8 +20,10 @@ header-y += prctl.h
header-y += processor-flags.h
header-y += ptrace-abi.h
header-y += sigcontext32.h
+header-y += svm.h
header-y += ucontext.h
header-y += vm86.h
+header-y += vmx.h
header-y += vsyscall.h
genhdr-y += unistd_32.h
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 831dbb9c6c02..41ab26ea6564 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -399,14 +399,17 @@ static inline void drop_init_fpu(struct task_struct *tsk)
typedef struct { int preload; } fpu_switch_t;
/*
- * FIXME! We could do a totally lazy restore, but we need to
- * add a per-cpu "this was the task that last touched the FPU
- * on this CPU" variable, and the task needs to have a "I last
- * touched the FPU on this CPU" and check them.
+ * Must be run with preemption disabled: this clears the fpu_owner_task,
+ * on this CPU.
*
- * We don't do that yet, so "fpu_lazy_restore()" always returns
- * false, but some day..
+ * This will disable any lazy FPU state restore of the current FPU state,
+ * but if the current thread owns the FPU, it will still be saved by.
*/
+static inline void __cpu_disable_lazy_restore(unsigned int cpu)
+{
+ per_cpu(fpu_owner_task, cpu) = NULL;
+}
+
static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
{
return new == this_cpu_read_stable(fpu_owner_task) &&
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index dcfde52979c3..19f16ebaf4fa 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -205,21 +205,14 @@ static inline bool user_64bit_mode(struct pt_regs *regs)
}
#endif
-/*
- * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode
- * when it traps. The previous stack will be directly underneath the saved
- * registers, and 'sp/ss' won't even have been saved. Thus the '&regs->sp'.
- *
- * This is valid only for kernel mode traps.
- */
-static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
-{
#ifdef CONFIG_X86_32
- return (unsigned long)(&regs->sp);
+extern unsigned long kernel_stack_pointer(struct pt_regs *regs);
#else
+static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
+{
return regs->sp;
-#endif
}
+#endif
#define GET_IP(regs) ((regs)->ip)
#define GET_FP(regs) ((regs)->bp)
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index f7e98a2c0d12..1b7d1656a042 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -631,6 +631,20 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
}
}
+ /*
+ * The way access filter has a performance penalty on some workloads.
+ * Disable it on the affected CPUs.
+ */
+ if ((c->x86 == 0x15) &&
+ (c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
+ u64 val;
+
+ if (!rdmsrl_safe(0xc0011021, &val) && !(val & 0x1E)) {
+ val |= 0x1E;
+ wrmsrl_safe(0xc0011021, val);
+ }
+ }
+
cpu_detect_cache_sizes(c);
/* Multi core CPU? */
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 698b6ec12e0f..1ac581f38dfa 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -6,7 +6,7 @@
*
* Written by Jacob Shin - AMD, Inc.
*
- * Support: borislav.petkov@amd.com
+ * Maintained by: Borislav Petkov <bp@alien8.de>
*
* April 2006
* - added support for AMD Family 0x10 processors
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index 5f88abf07e9c..4f9a3cbfc4a3 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -285,34 +285,39 @@ void cmci_clear(void)
raw_spin_unlock_irqrestore(&cmci_discover_lock, flags);
}
+static long 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)
{
- int banks;
- int cpu;
- cpumask_var_t old;
+ int cpu, banks;
if (!cmci_supported(&banks))
return;
- if (!alloc_cpumask_var(&old, GFP_KERNEL))
- return;
- cpumask_copy(old, &current->cpus_allowed);
for_each_online_cpu(cpu) {
if (cpu == dying)
continue;
- if (set_cpus_allowed_ptr(current, cpumask_of(cpu)))
+
+ if (cpu == smp_processor_id()) {
+ cmci_rediscover_work_func(NULL);
continue;
- /* Recheck banks in case CPUs don't all have the same */
- if (cmci_supported(&banks))
- cmci_discover(banks);
- }
+ }
- set_cpus_allowed_ptr(current, old);
- free_cpumask_var(old);
+ work_on_cpu(cpu, cmci_rediscover_work_func, NULL);
+ }
}
/*
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index b51b2c7ee51f..1328fe49a3f1 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -995,8 +995,8 @@ END(interrupt)
*/
.p2align CONFIG_X86_L1_CACHE_SHIFT
common_interrupt:
- ASM_CLAC
XCPT_FRAME
+ ASM_CLAC
addq $-0x80,(%rsp) /* Adjust vector to [-256,-1] range */
interrupt do_IRQ
/* 0(%rsp): old_rsp-ARGOFFSET */
@@ -1135,8 +1135,8 @@ END(common_interrupt)
*/
.macro apicinterrupt num sym do_sym
ENTRY(\sym)
- ASM_CLAC
INTR_FRAME
+ ASM_CLAC
pushq_cfi $~(\num)
.Lcommon_\sym:
interrupt \do_sym
@@ -1190,8 +1190,8 @@ apicinterrupt IRQ_WORK_VECTOR \
*/
.macro zeroentry sym do_sym
ENTRY(\sym)
- ASM_CLAC
INTR_FRAME
+ ASM_CLAC
PARAVIRT_ADJUST_EXCEPTION_FRAME
pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */
subq $ORIG_RAX-R15, %rsp
@@ -1208,8 +1208,8 @@ END(\sym)
.macro paranoidzeroentry sym do_sym
ENTRY(\sym)
- ASM_CLAC
INTR_FRAME
+ ASM_CLAC
PARAVIRT_ADJUST_EXCEPTION_FRAME
pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */
subq $ORIG_RAX-R15, %rsp
@@ -1227,8 +1227,8 @@ END(\sym)
#define INIT_TSS_IST(x) PER_CPU_VAR(init_tss) + (TSS_ist + ((x) - 1) * 8)
.macro paranoidzeroentry_ist sym do_sym ist
ENTRY(\sym)
- ASM_CLAC
INTR_FRAME
+ ASM_CLAC
PARAVIRT_ADJUST_EXCEPTION_FRAME
pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */
subq $ORIG_RAX-R15, %rsp
@@ -1247,8 +1247,8 @@ END(\sym)
.macro errorentry sym do_sym
ENTRY(\sym)
- ASM_CLAC
XCPT_FRAME
+ ASM_CLAC
PARAVIRT_ADJUST_EXCEPTION_FRAME
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
@@ -1266,8 +1266,8 @@ END(\sym)
/* error code is on the stack already */
.macro paranoiderrorentry sym do_sym
ENTRY(\sym)
- ASM_CLAC
XCPT_FRAME
+ ASM_CLAC
PARAVIRT_ADJUST_EXCEPTION_FRAME
subq $ORIG_RAX-R15, %rsp
CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 957a47aec64e..4dac2f68ed4a 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -292,8 +292,8 @@ default_entry:
* be using the global pages.
*
* NOTE! If we are on a 486 we may have no cr4 at all!
- * Specifically, cr4 exists if and only if CPUID exists,
- * which in turn exists if and only if EFLAGS.ID exists.
+ * Specifically, cr4 exists if and only if CPUID exists
+ * and has flags other than the FPU flag set.
*/
movl $X86_EFLAGS_ID,%ecx
pushl %ecx
@@ -308,6 +308,11 @@ default_entry:
testl %ecx,%eax
jz 6f # No ID flag = no CPUID = no CR4
+ movl $1,%eax
+ cpuid
+ andl $~1,%edx # Ignore CPUID.FPU
+ jz 6f # No flags or only CPUID.FPU = no CR4
+
movl pa(mmu_cr4_features),%eax
movl %eax,%cr4
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
index 7720ff5a9ee2..efdec7cd8e01 100644
--- a/arch/x86/kernel/microcode_amd.c
+++ b/arch/x86/kernel/microcode_amd.c
@@ -8,8 +8,8 @@
* Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
*
* Maintainers:
- * Andreas Herrmann <andreas.herrmann3@amd.com>
- * Borislav Petkov <borislav.petkov@amd.com>
+ * Andreas Herrmann <herrmann.der.user@googlemail.com>
+ * Borislav Petkov <bp@alien8.de>
*
* This driver allows to upgrade microcode on F10h AMD
* CPUs and later.
@@ -190,6 +190,7 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size,
#define F1XH_MPB_MAX_SIZE 2048
#define F14H_MPB_MAX_SIZE 1824
#define F15H_MPB_MAX_SIZE 4096
+#define F16H_MPB_MAX_SIZE 3458
switch (c->x86) {
case 0x14:
@@ -198,6 +199,9 @@ static unsigned int verify_patch_size(int cpu, u32 patch_size,
case 0x15:
max_size = F15H_MPB_MAX_SIZE;
break;
+ case 0x16:
+ max_size = F16H_MPB_MAX_SIZE;
+ break;
default:
max_size = F1XH_MPB_MAX_SIZE;
break;
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index b00b33a18390..974b67e46dd0 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -22,6 +22,7 @@
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
#include <linux/rcupdate.h>
+#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -166,6 +167,35 @@ static inline bool invalid_selector(u16 value)
#define FLAG_MASK FLAG_MASK_32
+/*
+ * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode
+ * when it traps. The previous stack will be directly underneath the saved
+ * registers, and 'sp/ss' won't even have been saved. Thus the '&regs->sp'.
+ *
+ * Now, if the stack is empty, '&regs->sp' is out of range. In this
+ * case we try to take the previous stack. To always return a non-null
+ * stack pointer we fall back to regs as stack if no previous stack
+ * exists.
+ *
+ * This is valid only for kernel mode traps.
+ */
+unsigned long kernel_stack_pointer(struct pt_regs *regs)
+{
+ unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1);
+ unsigned long sp = (unsigned long)&regs->sp;
+ struct thread_info *tinfo;
+
+ if (context == (sp & ~(THREAD_SIZE - 1)))
+ return sp;
+
+ tinfo = (struct thread_info *)context;
+ if (tinfo->previous_esp)
+ return tinfo->previous_esp;
+
+ return (unsigned long)regs;
+}
+EXPORT_SYMBOL_GPL(kernel_stack_pointer);
+
static unsigned long *pt_regs_access(struct pt_regs *regs, unsigned long regno)
{
BUILD_BUG_ON(offsetof(struct pt_regs, bx) != 0);
@@ -1511,6 +1541,13 @@ void syscall_trace_leave(struct pt_regs *regs)
{
bool step;
+ /*
+ * We may come here right after calling schedule_user()
+ * or do_notify_resume(), in which case we can be in RCU
+ * user mode.
+ */
+ rcu_user_exit();
+
audit_syscall_exit(regs);
if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c80a33bc528b..f3e2ec878b8c 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -68,6 +68,8 @@
#include <asm/mwait.h>
#include <asm/apic.h>
#include <asm/io_apic.h>
+#include <asm/i387.h>
+#include <asm/fpu-internal.h>
#include <asm/setup.h>
#include <asm/uv/uv.h>
#include <linux/mc146818rtc.h>
@@ -818,6 +820,9 @@ int __cpuinit native_cpu_up(unsigned int cpu, struct task_struct *tidle)
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+ /* the FPU context is blank, nobody can own it */
+ __cpu_disable_lazy_restore(cpu);
+
err = do_boot_cpu(apicid, cpu, tidle);
if (err) {
pr_debug("do_boot_cpu failed %d\n", err);
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index a10e46016851..58fc51488828 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -24,6 +24,9 @@ static inline bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
+ if (!static_cpu_has(X86_FEATURE_XSAVE))
+ return 0;
+
best = kvm_find_cpuid_entry(vcpu, 1, 0);
return best && (best->ecx & bit(X86_FEATURE_XSAVE));
}
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 39171cb307ea..bba39bfa1c4b 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -426,8 +426,7 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
_ASM_EXTABLE(1b, 3b) \
: "=m" ((ctxt)->eflags), "=&r" (_tmp), \
"+a" (*rax), "+d" (*rdx), "+qm"(_ex) \
- : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val), \
- "a" (*rax), "d" (*rdx)); \
+ : "i" (EFLAGS_MASK), "m" ((ctxt)->src.val)); \
} while (0)
/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ad6b1dd06f8b..f85815945fc6 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -6549,19 +6549,22 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
}
}
- exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
/* Exposing INVPCID only when PCID is exposed */
best = kvm_find_cpuid_entry(vcpu, 0x7, 0);
if (vmx_invpcid_supported() &&
best && (best->ebx & bit(X86_FEATURE_INVPCID)) &&
guest_cpuid_has_pcid(vcpu)) {
+ exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
exec_control |= SECONDARY_EXEC_ENABLE_INVPCID;
vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
exec_control);
} else {
- exec_control &= ~SECONDARY_EXEC_ENABLE_INVPCID;
- vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
- exec_control);
+ if (cpu_has_secondary_exec_ctrls()) {
+ exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
+ exec_control &= ~SECONDARY_EXEC_ENABLE_INVPCID;
+ vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
+ exec_control);
+ }
if (best)
best->ebx &= ~bit(X86_FEATURE_INVPCID);
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 224a7e78cb6c..4f7641756be2 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5781,6 +5781,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
int pending_vec, max_bits, idx;
struct desc_ptr dt;
+ if (!guest_cpuid_has_xsave(vcpu) && (sregs->cr4 & X86_CR4_OSXSAVE))
+ return -EINVAL;
+
dt.size = sregs->idt.limit;
dt.address = sregs->idt.base;
kvm_x86_ops->set_idt(vcpu, &dt);
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index 0777f042e400..60f926cd8b0e 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -197,7 +197,7 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
}
if (end == TLB_FLUSH_ALL || tlb_flushall_shift == -1
- || vmflag == VM_HUGETLB) {
+ || vmflag & VM_HUGETLB) {
local_flush_tlb();
goto flush_all;
}
diff --git a/arch/x86/pci/ce4100.c b/arch/x86/pci/ce4100.c
index 41bd2a2d2c50..b914e20b5a00 100644
--- a/arch/x86/pci/ce4100.c
+++ b/arch/x86/pci/ce4100.c
@@ -115,6 +115,16 @@ static void sata_revid_read(struct sim_dev_reg *reg, u32 *value)
reg_read(reg, value);
}
+static void reg_noirq_read(struct sim_dev_reg *reg, u32 *value)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&pci_config_lock, flags);
+ /* force interrupt pin value to 0 */
+ *value = reg->sim_reg.value & 0xfff00ff;
+ raw_spin_unlock_irqrestore(&pci_config_lock, flags);
+}
+
static struct sim_dev_reg bus1_fixups[] = {
DEFINE_REG(2, 0, 0x10, (16*MB), reg_init, reg_read, reg_write)
DEFINE_REG(2, 0, 0x14, (256), reg_init, reg_read, reg_write)
@@ -144,6 +154,7 @@ static struct sim_dev_reg bus1_fixups[] = {
DEFINE_REG(11, 5, 0x10, (64*KB), reg_init, reg_read, reg_write)
DEFINE_REG(11, 6, 0x10, (256), reg_init, reg_read, reg_write)
DEFINE_REG(11, 7, 0x10, (64*KB), reg_init, reg_read, reg_write)
+ DEFINE_REG(11, 7, 0x3c, 256, reg_init, reg_noirq_read, reg_write)
DEFINE_REG(12, 0, 0x10, (128*KB), reg_init, reg_read, reg_write)
DEFINE_REG(12, 0, 0x14, (256), reg_init, reg_read, reg_write)
DEFINE_REG(12, 1, 0x10, (1024), reg_init, reg_read, reg_write)
@@ -161,8 +172,10 @@ static struct sim_dev_reg bus1_fixups[] = {
DEFINE_REG(16, 0, 0x10, (64*KB), reg_init, reg_read, reg_write)
DEFINE_REG(16, 0, 0x14, (64*MB), reg_init, reg_read, reg_write)
DEFINE_REG(16, 0, 0x18, (64*MB), reg_init, reg_read, reg_write)
+ DEFINE_REG(16, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write)
DEFINE_REG(17, 0, 0x10, (128*KB), reg_init, reg_read, reg_write)
DEFINE_REG(18, 0, 0x10, (1*KB), reg_init, reg_read, reg_write)
+ DEFINE_REG(18, 0, 0x3c, 256, reg_init, reg_noirq_read, reg_write)
};
static void __init init_sim_regs(void)
diff --git a/arch/x86/platform/ce4100/ce4100.c b/arch/x86/platform/ce4100/ce4100.c
index 4c61b52191eb..92525cb8e54c 100644
--- a/arch/x86/platform/ce4100/ce4100.c
+++ b/arch/x86/platform/ce4100/ce4100.c
@@ -21,12 +21,25 @@
#include <asm/i8259.h>
#include <asm/io.h>
#include <asm/io_apic.h>
+#include <asm/emergency-restart.h>
static int ce4100_i8042_detect(void)
{
return 0;
}
+/*
+ * The CE4100 platform has an internal 8051 Microcontroller which is
+ * responsible for signaling to the external Power Management Unit the
+ * intention to reset, reboot or power off the system. This 8051 device has
+ * its command register mapped at I/O port 0xcf9 and the value 0x4 is used
+ * to power off the system.
+ */
+static void ce4100_power_off(void)
+{
+ outb(0x4, 0xcf9);
+}
+
#ifdef CONFIG_SERIAL_8250
static unsigned int mem_serial_in(struct uart_port *p, int offset)
@@ -139,8 +152,19 @@ void __init x86_ce4100_early_setup(void)
x86_init.mpparse.find_smp_config = x86_init_noop;
x86_init.pci.init = ce4100_pci_init;
+ /*
+ * By default, the reboot method is ACPI which is supported by the
+ * CE4100 bootloader CEFDK using FADT.ResetReg Address and ResetValue
+ * the bootloader will however issue a system power off instead of
+ * reboot. By using BOOT_KBD we ensure proper system reboot as
+ * expected.
+ */
+ reboot_type = BOOT_KBD;
+
#ifdef CONFIG_X86_IO_APIC
x86_init.pci.init_irq = sdv_pci_init;
x86_init.mpparse.setup_ioapic_ids = setup_ioapic_ids_from_mpc_nocheck;
#endif
+
+ pm_power_off = ce4100_power_off;
}
diff --git a/block/blk-exec.c b/block/blk-exec.c
index 8b6dc5bd4dd0..f71eac35c1b9 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -52,11 +52,17 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
rq_end_io_fn *done)
{
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
+ bool is_pm_resume;
WARN_ON(irqs_disabled());
rq->rq_disk = bd_disk;
rq->end_io = done;
+ /*
+ * need to check this before __blk_run_queue(), because rq can
+ * be freed before that returns.
+ */
+ is_pm_resume = rq->cmd_type == REQ_TYPE_PM_RESUME;
spin_lock_irq(q->queue_lock);
@@ -71,7 +77,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
__elv_add_request(q, rq, where);
__blk_run_queue(q);
/* the queue is stopped so it won't be run */
- if (rq->cmd_type == REQ_TYPE_PM_RESUME)
+ if (is_pm_resume)
q->request_fn(q);
spin_unlock_irq(q->queue_lock);
}
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index b1ae48054dc5..b7078afddb74 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -238,7 +238,7 @@ static int __devexit ahci_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ahci_suspend(struct device *dev)
{
struct ahci_platform_data *pdata = dev_get_platdata(dev);
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index fd9ecf74e631..5b0ba3f20edc 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -1105,10 +1105,15 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev,
struct acpi_device *acpi_dev;
struct acpi_device_power_state *states;
- if (ap->flags & ATA_FLAG_ACPI_SATA)
- ata_dev = &ap->link.device[sdev->channel];
- else
+ if (ap->flags & ATA_FLAG_ACPI_SATA) {
+ if (!sata_pmp_attached(ap))
+ ata_dev = &ap->link.device[sdev->id];
+ else
+ ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id];
+ }
+ else {
ata_dev = &ap->link.device[sdev->id];
+ }
*handle = ata_dev_acpi_handle(ata_dev);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3cc7096cfda7..f46fbd3bd3fb 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2942,6 +2942,10 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode)
if (xfer_mode == t->mode)
return t;
+
+ WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n",
+ __func__, xfer_mode);
+
return NULL;
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e3bda074fa12..a6df6a351d6e 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1052,6 +1052,8 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
+ sdev->no_report_opcodes = 1;
+ sdev->no_write_same = 1;
/* Schedule policy is determined by ->qc_defer() callback and
* it needs to see every deferred qc. Set dev_blocked to 1 to
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 26201ebef3ca..371fd2c698b7 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -317,6 +317,12 @@ static int cf_init(struct arasan_cf_dev *acdev)
return ret;
}
+ ret = clk_set_rate(acdev->clk, 166000000);
+ if (ret) {
+ dev_warn(acdev->host->dev, "clock set rate failed");
+ return ret;
+ }
+
spin_lock_irqsave(&acdev->host->lock, flags);
/* configure CF interface clock */
writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk :
@@ -908,7 +914,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int arasan_cf_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
index 0d7c4c2cd26f..400bf1c3e982 100644
--- a/drivers/ata/sata_highbank.c
+++ b/drivers/ata/sata_highbank.c
@@ -260,7 +260,7 @@ static const struct of_device_id ahci_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
-static int __init ahci_highbank_probe(struct platform_device *pdev)
+static int __devinit ahci_highbank_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
@@ -378,7 +378,7 @@ static int __devexit ahci_highbank_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ahci_highbank_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 44a4256533e1..08608de87e4e 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -142,6 +142,39 @@ static int k2_sata_scr_write(struct ata_link *link,
return 0;
}
+static int k2_sata_softreset(struct ata_link *link,
+ unsigned int *class, unsigned long deadline)
+{
+ u8 dmactl;
+ void __iomem *mmio = link->ap->ioaddr.bmdma_addr;
+
+ dmactl = readb(mmio + ATA_DMA_CMD);
+
+ /* Clear the start bit */
+ if (dmactl & ATA_DMA_START) {
+ dmactl &= ~ATA_DMA_START;
+ writeb(dmactl, mmio + ATA_DMA_CMD);
+ }
+
+ return ata_sff_softreset(link, class, deadline);
+}
+
+static int k2_sata_hardreset(struct ata_link *link,
+ unsigned int *class, unsigned long deadline)
+{
+ u8 dmactl;
+ void __iomem *mmio = link->ap->ioaddr.bmdma_addr;
+
+ dmactl = readb(mmio + ATA_DMA_CMD);
+
+ /* Clear the start bit */
+ if (dmactl & ATA_DMA_START) {
+ dmactl &= ~ATA_DMA_START;
+ writeb(dmactl, mmio + ATA_DMA_CMD);
+ }
+
+ return sata_sff_hardreset(link, class, deadline);
+}
static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
{
@@ -346,6 +379,8 @@ static struct scsi_host_template k2_sata_sht = {
static struct ata_port_operations k2_sata_ops = {
.inherits = &ata_bmdma_port_ops,
+ .softreset = k2_sata_softreset,
+ .hardreset = k2_sata_hardreset,
.sff_tf_load = k2_sata_tf_load,
.sff_tf_read = k2_sata_tf_read,
.sff_check_status = k2_stat_check_status,
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 89b30f32ba68..ff7bb8a42ed6 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1961,6 +1961,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
res = loader_verify(lb, dev, rec);
if (res)
break;
+ rec = ihex_next_binrec(rec);
}
release_firmware(fw);
if (!res)
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 612afcc5a938..0ca54421ce97 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -57,8 +57,8 @@ struct cma *dma_contiguous_default_area;
* Users, who want to set the size of global CMA area for their system
* should use cma= kernel parameter.
*/
-static const unsigned long size_bytes = CMA_SIZE_MBYTES * SZ_1M;
-static long size_cmdline = -1;
+static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M;
+static phys_addr_t size_cmdline = -1;
static int __init early_cma(char *p)
{
@@ -70,7 +70,7 @@ early_param("cma", early_cma);
#ifdef CONFIG_CMA_SIZE_PERCENTAGE
-static unsigned long __init __maybe_unused cma_early_percent_memory(void)
+static phys_addr_t __init __maybe_unused cma_early_percent_memory(void)
{
struct memblock_region *reg;
unsigned long total_pages = 0;
@@ -88,7 +88,7 @@ static unsigned long __init __maybe_unused cma_early_percent_memory(void)
#else
-static inline __maybe_unused unsigned long cma_early_percent_memory(void)
+static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
{
return 0;
}
@@ -106,7 +106,7 @@ static inline __maybe_unused unsigned long cma_early_percent_memory(void)
*/
void __init dma_contiguous_reserve(phys_addr_t limit)
{
- unsigned long selected_size = 0;
+ phys_addr_t selected_size = 0;
pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);
@@ -126,7 +126,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
if (selected_size) {
pr_debug("%s: reserving %ld MiB for global area\n", __func__,
- selected_size / SZ_1M);
+ (unsigned long)selected_size / SZ_1M);
dma_declare_contiguous(NULL, selected_size, 0, limit);
}
@@ -227,11 +227,11 @@ core_initcall(cma_init_reserved_areas);
* called by board specific code when early allocator (memblock or bootmem)
* is still activate.
*/
-int __init dma_declare_contiguous(struct device *dev, unsigned long size,
+int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit)
{
struct cma_reserved *r = &cma_reserved[cma_reserved_count];
- unsigned long alignment;
+ phys_addr_t alignment;
pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
(unsigned long)size, (unsigned long)base,
@@ -268,10 +268,6 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size,
if (!addr) {
base = -ENOMEM;
goto err;
- } else if (addr + size > ~(unsigned long)0) {
- memblock_free(addr, size);
- base = -EINVAL;
- goto err;
} else {
base = addr;
}
@@ -285,14 +281,14 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size,
r->size = size;
r->dev = dev;
cma_reserved_count++;
- pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M,
+ pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
(unsigned long)base);
/* Architecture specific contiguous memory fixup. */
dma_contiguous_early_fixup(base, size);
return 0;
err:
- pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M);
+ pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
return base;
}
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 74a67e0019a2..fbbd4ed2edf2 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -451,7 +451,7 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
if (ancestor)
error = dev_pm_qos_add_request(ancestor, req, value);
- if (error)
+ if (error < 0)
req->dev = NULL;
return error;
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 3804a0af3ef1..9fe4f1865558 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -935,7 +935,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail)
/* cf. http://lkml.org/lkml/2006/10/31/28 */
if (!fastfail)
- q->request_fn(q);
+ __blk_run_queue(q);
}
static void
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 1c49d7173966..2ddd64a9ffde 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4330,6 +4330,7 @@ out_unreg_region:
out_unreg_blkdev:
unregister_blkdev(FLOPPY_MAJOR, "fd");
out_put_disk:
+ destroy_workqueue(floppy_wq);
for (drive = 0; drive < N_DRIVE; drive++) {
if (!disks[drive])
break;
@@ -4340,7 +4341,6 @@ out_put_disk:
}
put_disk(disks[drive]);
}
- destroy_workqueue(floppy_wq);
return err;
}
@@ -4555,6 +4555,8 @@ static void __exit floppy_module_exit(void)
unregister_blkdev(FLOPPY_MAJOR, "fd");
platform_driver_unregister(&floppy_driver);
+ destroy_workqueue(floppy_wq);
+
for (drive = 0; drive < N_DRIVE; drive++) {
del_timer_sync(&motor_off_timer[drive]);
@@ -4578,7 +4580,6 @@ static void __exit floppy_module_exit(void)
cancel_delayed_work_sync(&fd_timeout);
cancel_delayed_work_sync(&fd_timer);
- destroy_workqueue(floppy_wq);
if (atomic_read(&usage_count))
floppy_release_irq_and_dma();
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index adc6f36564cf..9694dd99bbbc 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -559,7 +559,7 @@ static void mtip_timeout_function(unsigned long int data)
struct mtip_cmd *command;
int tag, cmdto_cnt = 0;
unsigned int bit, group;
- unsigned int num_command_slots = port->dd->slot_groups * 32;
+ unsigned int num_command_slots;
unsigned long to, tagaccum[SLOTBITS_IN_LONGS];
if (unlikely(!port))
@@ -572,6 +572,7 @@ static void mtip_timeout_function(unsigned long int data)
}
/* clear the tag accumulator */
memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long));
+ num_command_slots = port->dd->slot_groups * 32;
for (tag = 0; tag < num_command_slots; tag++) {
/*
@@ -2218,8 +2219,8 @@ static int exec_drive_taskfile(struct driver_data *dd,
fis.device);
/* check for erase mode support during secure erase.*/
- if ((fis.command == ATA_CMD_SEC_ERASE_UNIT)
- && (outbuf[0] & MTIP_SEC_ERASE_MODE)) {
+ if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) && outbuf &&
+ (outbuf[0] & MTIP_SEC_ERASE_MODE)) {
erasemode = 1;
}
@@ -2439,7 +2440,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd,
* return value
* None
*/
-static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
+static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
int nsect, int nents, int tag, void *callback,
void *data, int dir)
{
@@ -2447,6 +2448,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
struct mtip_port *port = dd->port;
struct mtip_cmd *command = &port->commands[tag];
int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ u64 start = sector;
/* Map the scatter list for DMA access */
nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir);
@@ -2465,8 +2467,12 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start,
fis->opts = 1 << 7;
fis->command =
(dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE);
- *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF);
- *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF);
+ fis->lba_low = start & 0xFF;
+ fis->lba_mid = (start >> 8) & 0xFF;
+ fis->lba_hi = (start >> 16) & 0xFF;
+ fis->lba_low_ex = (start >> 24) & 0xFF;
+ fis->lba_mid_ex = (start >> 32) & 0xFF;
+ fis->lba_hi_ex = (start >> 40) & 0xFF;
fis->device = 1 << 6;
fis->features = nsect & 0xFF;
fis->features_ex = (nsect >> 8) & 0xFF;
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index 5f4a917bd8bb..b1742640556a 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -34,7 +34,7 @@
#define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48
/* check for erase mode support during secure erase */
-#define MTIP_SEC_ERASE_MODE 0x3
+#define MTIP_SEC_ERASE_MODE 0x2
/* # of times to retry timed out/failed IOs */
#define MTIP_MAX_RETRIES 2
@@ -155,14 +155,14 @@ enum {
MTIP_DDF_REBUILD_FAILED_BIT = 8,
};
-__packed struct smart_attr{
+struct smart_attr {
u8 attr_id;
u16 flags;
u8 cur;
u8 worst;
u32 data;
u8 res[3];
-};
+} __packed;
/* Register Frame Information Structure (FIS), host to device. */
struct host_to_dev_fis {
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index fc2de5528dcc..b00000e8aef6 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -67,6 +67,7 @@ static struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3304) },
{ USB_DEVICE(0x0930, 0x0215) },
{ USB_DEVICE(0x0489, 0xE03D) },
+ { USB_DEVICE(0x0489, 0xE027) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index debda27df9b0..ee82f2fb65f0 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -124,6 +124,7 @@ static struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c
index ff63560b8467..0c48b0e05ed6 100644
--- a/drivers/bus/omap-ocp2scp.c
+++ b/drivers/bus/omap-ocp2scp.c
@@ -22,6 +22,26 @@
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/platform_data/omap_ocp2scp.h>
+
+/**
+ * _count_resources - count for the number of resources
+ * @res: struct resource *
+ *
+ * Count and return the number of resources populated for the device that is
+ * connected to ocp2scp.
+ */
+static unsigned _count_resources(struct resource *res)
+{
+ int cnt = 0;
+
+ while (res->start != res->end) {
+ cnt++;
+ res++;
+ }
+
+ return cnt;
+}
static int ocp2scp_remove_devices(struct device *dev, void *c)
{
@@ -34,20 +54,62 @@ static int ocp2scp_remove_devices(struct device *dev, void *c)
static int __devinit omap_ocp2scp_probe(struct platform_device *pdev)
{
- int ret;
- struct device_node *np = pdev->dev.of_node;
+ int ret;
+ unsigned res_cnt, i;
+ struct device_node *np = pdev->dev.of_node;
+ struct platform_device *pdev_child;
+ struct omap_ocp2scp_platform_data *pdata = pdev->dev.platform_data;
+ struct omap_ocp2scp_dev *dev;
if (np) {
ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
if (ret) {
- dev_err(&pdev->dev, "failed to add resources for ocp2scp child\n");
+ dev_err(&pdev->dev,
+ "failed to add resources for ocp2scp child\n");
goto err0;
}
+ } else if (pdata) {
+ for (i = 0, dev = *pdata->devices; i < pdata->dev_cnt; i++,
+ dev++) {
+ res_cnt = _count_resources(dev->res);
+
+ pdev_child = platform_device_alloc(dev->drv_name,
+ PLATFORM_DEVID_AUTO);
+ if (!pdev_child) {
+ dev_err(&pdev->dev,
+ "failed to allocate mem for ocp2scp child\n");
+ goto err0;
+ }
+
+ ret = platform_device_add_resources(pdev_child,
+ dev->res, res_cnt);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to add resources for ocp2scp child\n");
+ goto err1;
+ }
+
+ pdev_child->dev.parent = &pdev->dev;
+
+ ret = platform_device_add(pdev_child);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "failed to register ocp2scp child device\n");
+ goto err1;
+ }
+ }
+ } else {
+ dev_err(&pdev->dev, "OCP2SCP initialized without plat data\n");
+ return -EINVAL;
}
+
pm_runtime_enable(&pdev->dev);
return 0;
+err1:
+ platform_device_put(pdev_child);
+
err0:
device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index fbd9b2b850ef..c58ea9b80b1a 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -127,12 +127,12 @@ config HW_RANDOM_VIA
If unsure, say Y.
config HW_RANDOM_IXP4XX
- tristate "Intel IXP4xx NPU HW Random Number Generator support"
+ tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support"
depends on HW_RANDOM && ARCH_IXP4XX
default HW_RANDOM
---help---
- This driver provides kernel-side support for the Random
- Number Generator hardware found on the Intel IXP4xx NPU.
+ This driver provides kernel-side support for the Pseudo-Random
+ Number Generator hardware found on the Intel IXP45x/46x NPU.
To compile this driver as a module, choose M here: the
module will be called ixp4xx-rng.
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
index 263567f5f392..beec1627db3c 100644
--- a/drivers/char/hw_random/ixp4xx-rng.c
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -45,6 +45,9 @@ static int __init ixp4xx_rng_init(void)
void __iomem * rng_base;
int err;
+ if (!cpu_is_ixp46x()) /* includes IXP455 */
+ return -ENOSYS;
+
rng_base = ioremap(0x70002100, 4);
if (!rng_base)
return -ENOMEM;
@@ -68,5 +71,5 @@ module_init(ixp4xx_rng_init);
module_exit(ixp4xx_rng_exit);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx");
+MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 0bb207eaef2f..54a3a6d09819 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd,
static const struct file_operations raw_fops = {
.read = do_sync_read,
- .aio_read = blkdev_aio_read,
+ .aio_read = generic_file_aio_read,
.write = do_sync_write,
.aio_write = blkdev_aio_write,
.fsync = blkdev_fsync,
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index bace9e98f75d..823f62d900ba 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -42,10 +42,12 @@ config COMMON_CLK_WM831X
config COMMON_CLK_VERSATILE
bool "Clock driver for ARM Reference designs"
- depends on ARCH_INTEGRATOR || ARCH_REALVIEW
+ depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
---help---
- Supports clocking on ARM Reference designs Integrator/AP,
- Integrator/CP, RealView PB1176, EB, PB11MP and PBX.
+ Supports clocking on ARM Reference designs:
+ - Integrator/AP and Integrator/CP
+ - RealView PB1176, EB, PB11MP and PBX
+ - Versatile Express
config COMMON_CLK_MAX77686
tristate "Clock driver for Maxim 77686 MFD"
@@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686
---help---
This driver supports Maxim 77686 crystal oscillator clock.
+config CLK_TWL6040
+ tristate "External McPDM functional clock from twl6040"
+ depends on TWL6040_CORE
+ ---help---
+ Enable the external functional clock support on OMAP4+ platforms for
+ McPDM. McPDM module is using the external bit clock on the McPDM bus
+ as functional clock.
+
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71a25b91de00..2701235d5757 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -23,3 +23,4 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
# Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
+obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c
index 67ad16b20b81..b61ee2c5af84 100644
--- a/drivers/clk/clk-bcm2835.c
+++ b/drivers/clk/clk-bcm2835.c
@@ -33,17 +33,17 @@ void __init bcm2835_init_clocks(void)
clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT,
250000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("sys_pclk not registered\n");
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT,
126000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("apb_pclk not registered\n");
clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT,
3000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("uart0_pclk not registered\n");
ret = clk_register_clkdev(clk, NULL, "20201000.uart");
if (ret)
@@ -51,7 +51,7 @@ void __init bcm2835_init_clocks(void)
clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT,
125000000);
- if (!clk)
+ if (IS_ERR(clk))
pr_err("uart1_pclk not registered\n");
ret = clk_register_clkdev(clk, NULL, "20215000.uart");
if (ret)
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index f5ec0eebd4d7..af78ed6b67ef 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
- if (clk)
+ if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
index 517874fa6858..a203ecccdc4f 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/clk-prima2.c
@@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void)
/* These are always available (RTC and 26MHz OSC)*/
clk = clk_register_fixed_rate(NULL, "rtc", NULL,
CLK_IS_ROOT, 32768);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register_fixed_rate(NULL, "osc", NULL,
CLK_IS_ROOT, 26000000);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll2.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_pll3.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mem.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_sys.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_security.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b8030000.security");
clk = clk_register(NULL, &clk_dsp.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_gps.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "a8010000.gps");
clk = clk_register(NULL, &clk_mf.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_io.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "io");
clk = clk_register(NULL, &clk_cpu.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "cpu");
clk = clk_register(NULL, &clk_uart0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0050000.uart");
clk = clk_register(NULL, &clk_uart1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0060000.uart");
clk = clk_register(NULL, &clk_uart2.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0070000.uart");
clk = clk_register(NULL, &clk_tsc.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0110000.tsc");
clk = clk_register(NULL, &clk_i2c0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00e0000.i2c");
clk = clk_register(NULL, &clk_i2c1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00f0000.i2c");
clk = clk_register(NULL, &clk_spi0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00d0000.spi");
clk = clk_register(NULL, &clk_spi1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0170000.spi");
clk = clk_register(NULL, &clk_pwmc.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0130000.pwm");
clk = clk_register(NULL, &clk_efuse.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0140000.efusesys");
clk = clk_register(NULL, &clk_pulse.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0150000.pulsec");
clk = clk_register(NULL, &clk_dmac0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
clk = clk_register(NULL, &clk_dmac1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
clk = clk_register(NULL, &clk_nand.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0030000.nand");
clk = clk_register(NULL, &clk_audio.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0040000.audio");
clk = clk_register(NULL, &clk_usp0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0080000.usp");
clk = clk_register(NULL, &clk_usp1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b0090000.usp");
clk = clk_register(NULL, &clk_usp2.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00a0000.usp");
clk = clk_register(NULL, &clk_vip.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00c0000.vip");
clk = clk_register(NULL, &clk_gfx.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "98000000.graphics");
clk = clk_register(NULL, &clk_mm.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "a0000000.multimedia");
clk = clk_register(NULL, &clk_lcd.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "90010000.display");
clk = clk_register(NULL, &clk_vpp.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "90020000.vpp");
clk = clk_register(NULL, &clk_mmc01.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mmc23.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_mmc45.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &usb_pll_clk_hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_usb0.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00e0000.usb");
clk = clk_register(NULL, &clk_usb1.hw);
- BUG_ON(!clk);
+ BUG_ON(IS_ERR(clk));
clk_register_clkdev(clk, NULL, "b00f0000.usb");
}
diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c
new file mode 100644
index 000000000000..bc1e713e7b9c
--- /dev/null
+++ b/drivers/clk/clk-twl6040.c
@@ -0,0 +1,126 @@
+/*
+* TWL6040 clock module driver for OMAP4 McPDM functional clock
+*
+* Copyright (C) 2012 Texas Instruments Inc.
+* Peter Ujfalusi <peter.ujfalusi@ti.com>
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA
+*
+*/
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/twl6040.h>
+#include <linux/clk-provider.h>
+
+struct twl6040_clk {
+ struct twl6040 *twl6040;
+ struct device *dev;
+ struct clk_hw mcpdm_fclk;
+ struct clk *clk;
+ int enabled;
+};
+
+static int twl6040_bitclk_is_enabled(struct clk_hw *hw)
+{
+ struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+ mcpdm_fclk);
+ return twl6040_clk->enabled;
+}
+
+static int twl6040_bitclk_prepare(struct clk_hw *hw)
+{
+ struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+ mcpdm_fclk);
+ int ret;
+
+ ret = twl6040_power(twl6040_clk->twl6040, 1);
+ if (!ret)
+ twl6040_clk->enabled = 1;
+
+ return ret;
+}
+
+static void twl6040_bitclk_unprepare(struct clk_hw *hw)
+{
+ struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk,
+ mcpdm_fclk);
+ int ret;
+
+ ret = twl6040_power(twl6040_clk->twl6040, 0);
+ if (!ret)
+ twl6040_clk->enabled = 0;
+}
+
+static const struct clk_ops twl6040_mcpdm_ops = {
+ .is_enabled = twl6040_bitclk_is_enabled,
+ .prepare = twl6040_bitclk_prepare,
+ .unprepare = twl6040_bitclk_unprepare,
+};
+
+static struct clk_init_data wm831x_clkout_init = {
+ .name = "mcpdm_fclk",
+ .ops = &twl6040_mcpdm_ops,
+ .flags = CLK_IS_ROOT,
+};
+
+static int __devinit twl6040_clk_probe(struct platform_device *pdev)
+{
+ struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent);
+ struct twl6040_clk *clkdata;
+
+ clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
+ if (!clkdata)
+ return -ENOMEM;
+
+ clkdata->dev = &pdev->dev;
+ clkdata->twl6040 = twl6040;
+
+ clkdata->mcpdm_fclk.init = &wm831x_clkout_init;
+ clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk);
+ if (IS_ERR(clkdata->clk))
+ return PTR_ERR(clkdata->clk);
+
+ dev_set_drvdata(&pdev->dev, clkdata);
+
+ return 0;
+}
+
+static int __devexit twl6040_clk_remove(struct platform_device *pdev)
+{
+ struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
+
+ clk_unregister(clkdata->clk);
+
+ return 0;
+}
+
+static struct platform_driver twl6040_clk_driver = {
+ .driver = {
+ .name = "twl6040-clk",
+ .owner = THIS_MODULE,
+ },
+ .probe = twl6040_clk_probe,
+ .remove = __devexit_p(twl6040_clk_remove),
+};
+
+module_platform_driver(twl6040_clk_driver);
+
+MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
+MODULE_ALIAS("platform:twl6040-clk");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index a885600f5270..fe25570874d6 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -120,8 +120,17 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw,
static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
+ struct clk_device *cdev = to_clk_device(hw);
u32 divisor = *prate / rate;
+ /*
+ * If this is a request for SDMMC we have to adjust the divisor
+ * when >31 to use the fixed predivisor
+ */
+ if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
+ divisor = 64 * ((divisor / 64) + 1);
+ }
+
return *prate / divisor;
}
@@ -135,6 +144,15 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
if (divisor == cdev->div_mask + 1)
divisor = 0;
+ /* SDMMC mask may need to be corrected before testing if its valid */
+ if ((cdev->div_mask == 0x3F) && (divisor > 31)) {
+ /*
+ * Bit 5 is a fixed /64 predivisor. If the requested divisor
+ * is >31 then correct for the fixed divisor being required.
+ */
+ divisor = 0x20 + (divisor / 64);
+ }
+
if (divisor > cdev->div_mask) {
pr_err("%s: invalid divisor for clock\n", __func__);
return -EINVAL;
diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c
index e7b7765e85f3..db4fbf20ffd7 100644
--- a/drivers/clk/clk-wm831x.c
+++ b/drivers/clk/clk-wm831x.c
@@ -370,43 +370,27 @@ static __devinit int wm831x_clk_probe(struct platform_device *pdev)
clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
clkdata->xtal_hw.init = &wm831x_xtal_init;
- clkdata->xtal = clk_register(&pdev->dev, &clkdata->xtal_hw);
- if (!clkdata->xtal)
- return -EINVAL;
+ clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw);
+ if (IS_ERR(clkdata->xtal))
+ return PTR_ERR(clkdata->xtal);
clkdata->fll_hw.init = &wm831x_fll_init;
- clkdata->fll = clk_register(&pdev->dev, &clkdata->fll_hw);
- if (!clkdata->fll) {
- ret = -EINVAL;
- goto err_xtal;
- }
+ clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw);
+ if (IS_ERR(clkdata->fll))
+ return PTR_ERR(clkdata->fll);
clkdata->clkout_hw.init = &wm831x_clkout_init;
- clkdata->clkout = clk_register(&pdev->dev, &clkdata->clkout_hw);
- if (!clkdata->clkout) {
- ret = -EINVAL;
- goto err_fll;
- }
+ clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw);
+ if (IS_ERR(clkdata->clkout))
+ return PTR_ERR(clkdata->clkout);
dev_set_drvdata(&pdev->dev, clkdata);
return 0;
-
-err_fll:
- clk_unregister(clkdata->fll);
-err_xtal:
- clk_unregister(clkdata->xtal);
- return ret;
}
static int __devexit wm831x_clk_remove(struct platform_device *pdev)
{
- struct wm831x_clk *clkdata = dev_get_drvdata(&pdev->dev);
-
- clk_unregister(clkdata->clkout);
- clk_unregister(clkdata->fll);
- clk_unregister(clkdata->xtal);
-
return 0;
}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 56e4495ebeb1..251e45d6024d 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -17,6 +17,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/device.h>
static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock);
@@ -218,8 +219,17 @@ static void clk_disable_unused_subtree(struct clk *clk)
if (clk->flags & CLK_IGNORE_UNUSED)
goto unlock_out;
- if (__clk_is_enabled(clk) && clk->ops->disable)
- clk->ops->disable(clk->hw);
+ /*
+ * some gate clocks have special needs during the disable-unused
+ * sequence. call .disable_unused if available, otherwise fall
+ * back to .disable
+ */
+ if (__clk_is_enabled(clk)) {
+ if (clk->ops->disable_unused)
+ clk->ops->disable_unused(clk->hw);
+ else if (clk->ops->disable)
+ clk->ops->disable(clk->hw);
+ }
unlock_out:
spin_unlock_irqrestore(&enable_lock, flags);
@@ -261,7 +271,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk)
inline u8 __clk_get_num_parents(struct clk *clk)
{
- return !clk ? -EINVAL : clk->num_parents;
+ return !clk ? 0 : clk->num_parents;
}
inline struct clk *__clk_get_parent(struct clk *clk)
@@ -269,14 +279,14 @@ inline struct clk *__clk_get_parent(struct clk *clk)
return !clk ? NULL : clk->parent;
}
-inline int __clk_get_enable_count(struct clk *clk)
+inline unsigned int __clk_get_enable_count(struct clk *clk)
{
- return !clk ? -EINVAL : clk->enable_count;
+ return !clk ? 0 : clk->enable_count;
}
-inline int __clk_get_prepare_count(struct clk *clk)
+inline unsigned int __clk_get_prepare_count(struct clk *clk)
{
- return !clk ? -EINVAL : clk->prepare_count;
+ return !clk ? 0 : clk->prepare_count;
}
unsigned long __clk_get_rate(struct clk *clk)
@@ -302,15 +312,15 @@ out:
inline unsigned long __clk_get_flags(struct clk *clk)
{
- return !clk ? -EINVAL : clk->flags;
+ return !clk ? 0 : clk->flags;
}
-int __clk_is_enabled(struct clk *clk)
+bool __clk_is_enabled(struct clk *clk)
{
int ret;
if (!clk)
- return -EINVAL;
+ return false;
/*
* .is_enabled is only mandatory for clocks that gate
@@ -323,7 +333,7 @@ int __clk_is_enabled(struct clk *clk)
ret = clk->ops->is_enabled(clk->hw);
out:
- return ret;
+ return !!ret;
}
static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
@@ -568,7 +578,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
unsigned long parent_rate = 0;
if (!clk)
- return -EINVAL;
+ return 0;
if (!clk->ops->round_rate) {
if (clk->flags & CLK_SET_RATE_PARENT)
@@ -1297,12 +1307,20 @@ int __clk_init(struct device *dev, struct clk *clk)
* walk the list of orphan clocks and reparent any that are children of
* this clock
*/
- hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node)
+ hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node) {
+ if (orphan->ops->get_parent) {
+ i = orphan->ops->get_parent(orphan->hw);
+ if (!strcmp(clk->name, orphan->parent_names[i]))
+ __clk_reparent(orphan, clk);
+ continue;
+ }
+
for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) {
__clk_reparent(orphan, clk);
break;
}
+ }
/*
* optional platform-specific magic
@@ -1361,28 +1379,9 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
}
EXPORT_SYMBOL_GPL(__clk_register);
-/**
- * clk_register - allocate a new clock, register it and return an opaque cookie
- * @dev: device that is registering this clock
- * @hw: link to hardware-specific clock data
- *
- * clk_register is the primary interface for populating the clock tree with new
- * clock nodes. It returns a pointer to the newly allocated struct clk which
- * cannot be dereferenced by driver code but may be used in conjuction with the
- * rest of the clock API. In the event of an error clk_register will return an
- * error code; drivers must test for an error code after calling clk_register.
- */
-struct clk *clk_register(struct device *dev, struct clk_hw *hw)
+static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk)
{
int i, ret;
- struct clk *clk;
-
- clk = kzalloc(sizeof(*clk), GFP_KERNEL);
- if (!clk) {
- pr_err("%s: could not allocate clk\n", __func__);
- ret = -ENOMEM;
- goto fail_out;
- }
clk->name = kstrdup(hw->init->name, GFP_KERNEL);
if (!clk->name) {
@@ -1420,7 +1419,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
ret = __clk_init(dev, clk);
if (!ret)
- return clk;
+ return 0;
fail_parent_names_copy:
while (--i >= 0)
@@ -1429,6 +1428,36 @@ fail_parent_names_copy:
fail_parent_names:
kfree(clk->name);
fail_name:
+ return ret;
+}
+
+/**
+ * clk_register - allocate a new clock, register it and return an opaque cookie
+ * @dev: device that is registering this clock
+ * @hw: link to hardware-specific clock data
+ *
+ * clk_register is the primary interface for populating the clock tree with new
+ * clock nodes. It returns a pointer to the newly allocated struct clk which
+ * cannot be dereferenced by driver code but may be used in conjuction with the
+ * rest of the clock API. In the event of an error clk_register will return an
+ * error code; drivers must test for an error code after calling clk_register.
+ */
+struct clk *clk_register(struct device *dev, struct clk_hw *hw)
+{
+ int ret;
+ struct clk *clk;
+
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk) {
+ pr_err("%s: could not allocate clk\n", __func__);
+ ret = -ENOMEM;
+ goto fail_out;
+ }
+
+ ret = _clk_register(dev, hw, clk);
+ if (!ret)
+ return clk;
+
kfree(clk);
fail_out:
return ERR_PTR(ret);
@@ -1444,6 +1473,63 @@ EXPORT_SYMBOL_GPL(clk_register);
void clk_unregister(struct clk *clk) {}
EXPORT_SYMBOL_GPL(clk_unregister);
+static void devm_clk_release(struct device *dev, void *res)
+{
+ clk_unregister(res);
+}
+
+/**
+ * devm_clk_register - resource managed clk_register()
+ * @dev: device that is registering this clock
+ * @hw: link to hardware-specific clock data
+ *
+ * Managed clk_register(). Clocks returned from this function are
+ * automatically clk_unregister()ed on driver detach. See clk_register() for
+ * more information.
+ */
+struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw)
+{
+ struct clk *clk;
+ int ret;
+
+ clk = devres_alloc(devm_clk_release, sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ ret = _clk_register(dev, hw, clk);
+ if (!ret) {
+ devres_add(dev, clk);
+ } else {
+ devres_free(clk);
+ clk = ERR_PTR(ret);
+ }
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(devm_clk_register);
+
+static int devm_clk_match(struct device *dev, void *res, void *data)
+{
+ struct clk *c = res;
+ if (WARN_ON(!c))
+ return 0;
+ return c == data;
+}
+
+/**
+ * devm_clk_unregister - resource managed clk_unregister()
+ * @clk: clock to unregister
+ *
+ * Deallocate a clock allocated with devm_clk_register(). Normally
+ * this function will not need to be called and the resource management
+ * code will ensure that the resource is freed.
+ */
+void devm_clk_unregister(struct device *dev, struct clk *clk)
+{
+ WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk));
+}
+EXPORT_SYMBOL_GPL(devm_clk_unregister);
+
/*** clk rate change notifiers ***/
/**
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index f00dffb9ad60..8dd476e2a9c5 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -85,7 +85,7 @@ enum imx23_clk {
cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll,
emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div,
clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif,
- lcdif, etm, usb, usb_pwr,
+ lcdif, etm, usb, usb_phy,
clk_max
};
@@ -143,8 +143,8 @@ int __init mx23_clocks_init(void)
clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31);
clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31);
clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31);
- clks[usb] = mxs_clk_gate("usb", "usb_pwr", DIGCTRL, 2);
- clks[usb_pwr] = clk_register_gate(NULL, "usb_pwr", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock);
+ clks[usb] = mxs_clk_gate("usb", "usb_phy", DIGCTRL, 2);
+ clks[usb_phy] = clk_register_gate(NULL, "usb_phy", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock);
for (i = 0; i < ARRAY_SIZE(clks); i++)
if (IS_ERR(clks[i])) {
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index 42978f1b4bd2..db3af0874121 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -140,7 +140,7 @@ enum imx28_clk {
emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div,
clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0,
ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm,
- fec, can0, can1, usb0, usb1, usb0_pwr, usb1_pwr, enet_out,
+ fec, can0, can1, usb0, usb1, usb0_phy, usb1_phy, enet_out,
clk_max
};
@@ -218,10 +218,10 @@ int __init mx28_clocks_init(void)
clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30);
clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30);
clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28);
- clks[usb0] = mxs_clk_gate("usb0", "usb0_pwr", DIGCTRL, 2);
- clks[usb1] = mxs_clk_gate("usb1", "usb1_pwr", DIGCTRL, 16);
- clks[usb0_pwr] = clk_register_gate(NULL, "usb0_pwr", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock);
- clks[usb1_pwr] = clk_register_gate(NULL, "usb1_pwr", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock);
+ clks[usb0] = mxs_clk_gate("usb0", "usb0_phy", DIGCTRL, 2);
+ clks[usb1] = mxs_clk_gate("usb1", "usb1_phy", DIGCTRL, 16);
+ clks[usb0_phy] = clk_register_gate(NULL, "usb0_phy", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock);
+ clks[usb1_phy] = clk_register_gate(NULL, "usb1_phy", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock);
clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock);
for (i = 0; i < ARRAY_SIZE(clks); i++)
diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c
index 6756e7c3bc07..bdfb4421c643 100644
--- a/drivers/clk/spear/clk-aux-synth.c
+++ b/drivers/clk/spear/clk-aux-synth.c
@@ -179,7 +179,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name,
if (gate_name) {
struct clk *tgate_clk;
- tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg,
+ tgate_clk = clk_register_gate(NULL, gate_name, aux_name,
+ CLK_SET_RATE_PARENT, reg,
aux->masks->enable_bit, 0, lock);
if (IS_ERR_OR_NULL(tgate_clk))
goto free_aux;
diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c
index 5f1b6badeb15..1b9b65bca51e 100644
--- a/drivers/clk/spear/clk-vco-pll.c
+++ b/drivers/clk/spear/clk-vco-pll.c
@@ -147,7 +147,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate,
struct clk_pll *pll = to_clk_pll(hw);
struct pll_rate_tbl *rtbl = pll->vco->rtbl;
unsigned long flags = 0, val;
- int i;
+ int uninitialized_var(i);
clk_pll_round_rate_index(hw, drate, NULL, &i);
diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c
index 7cd63788d546..628b6d5ed3d9 100644
--- a/drivers/clk/spear/clk.c
+++ b/drivers/clk/spear/clk.c
@@ -32,5 +32,8 @@ long clk_round_rate_index(struct clk_hw *hw, unsigned long drate,
}
}
+ if ((*index) == rtbl_cnt)
+ (*index)--;
+
return rate;
}
diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c
index 0fcec2aae19c..147e25f00405 100644
--- a/drivers/clk/spear/spear1310_clock.c
+++ b/drivers/clk/spear/spear1310_clock.c
@@ -313,6 +313,20 @@ static struct aux_clk_masks i2s_sclk_masks = {
/* i2s prs1 aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl i2s_prs1_rtbl[] = {
/* For parent clk = 49.152 MHz */
+ {.xscale = 1, .yscale = 12, .eq = 0}, /* 2.048 MHz, smp freq = 8Khz */
+ {.xscale = 11, .yscale = 96, .eq = 0}, /* 2.816 MHz, smp freq = 11Khz */
+ {.xscale = 1, .yscale = 6, .eq = 0}, /* 4.096 MHz, smp freq = 16Khz */
+ {.xscale = 11, .yscale = 48, .eq = 0}, /* 5.632 MHz, smp freq = 22Khz */
+
+ /*
+ * with parent clk = 49.152, freq gen is 8.192 MHz, smp freq = 32Khz
+ * with parent clk = 12.288, freq gen is 2.048 MHz, smp freq = 8Khz
+ */
+ {.xscale = 1, .yscale = 3, .eq = 0},
+
+ /* For parent clk = 49.152 MHz */
+ {.xscale = 17, .yscale = 37, .eq = 0}, /* 11.289 MHz, smp freq = 44Khz*/
+
{.xscale = 1, .yscale = 2, .eq = 0}, /* 12.288 MHz */
};
@@ -374,9 +388,6 @@ void __init spear1310_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -401,7 +412,7 @@ void __init spear1310_clk_init(void)
clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_RTC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "fc900000.rtc");
+ clk_register_clkdev(clk, NULL, "e0580000.rtc");
/* clock derived from 24 or 25 MHz osc clk */
/* vco-pll */
@@ -483,13 +494,18 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "ddr_clk", NULL);
/* clock derived from pll1 clk */
- clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 2);
+ clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
+ CLK_SET_RATE_PARENT, 1, 2);
clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_fixed_factor(NULL, "wdt_clk", "cpu_clk", 0, 1,
2);
clk_register_clkdev(clk, NULL, "ec800620.wdt");
+ clk = clk_register_fixed_factor(NULL, "smp_twd_clk", "cpu_clk", 0, 1,
+ 2);
+ clk_register_clkdev(clk, NULL, "smp_twd");
+
clk = clk_register_fixed_factor(NULL, "ahb_clk", "pll1_clk", 0, 1,
6);
clk_register_clkdev(clk, "ahb_clk", NULL);
@@ -547,14 +563,14 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_UART_CLK_SHIFT, SPEAR1310_UART_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_UART_CLK_SHIFT,
+ SPEAR1310_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
- clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UART_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_UART_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "e0000000.serial");
clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk",
@@ -563,9 +579,9 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "sdhci_syn_clk", NULL);
clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SDHCI_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_SDHCI_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b3000000.sdhci");
clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk",
@@ -574,9 +590,9 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "cfxd_syn_clk", NULL);
clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CFXD_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_CFXD_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b2800000.cf");
clk_register_clkdev(clk, NULL, "arasan_xd");
@@ -587,9 +603,9 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
- ARRAY_SIZE(c3_parents), 0, SPEAR1310_PERIP_CLK_CFG,
- SPEAR1310_C3_CLK_SHIFT, SPEAR1310_C3_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+ SPEAR1310_PERIP_CLK_CFG, SPEAR1310_C3_CLK_SHIFT,
+ SPEAR1310_C3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "c3_mclk", NULL);
clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0,
@@ -615,7 +631,7 @@ void __init spear1310_clk_init(void)
ARRAY_SIZE(gmac_phy_parents), 0,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT,
SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.0");
+ clk_register_clkdev(clk, "stmmacphy.0", NULL);
/* clcd */
clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
@@ -630,22 +646,22 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "clcd_syn_clk", NULL);
clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
- ARRAY_SIZE(clcd_pixel_parents), 0,
+ ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT,
SPEAR1310_CLCD_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "clcd_pixel_clk", NULL);
+ clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CLCD_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "clcd_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e1000000.clcd");
/* i2s */
clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG,
SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK,
0, &_lock);
- clk_register_clkdev(clk, "i2s_src_clk", NULL);
+ clk_register_clkdev(clk, "i2s_src_mclk", NULL);
clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
SPEAR1310_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl,
@@ -653,10 +669,10 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1310_I2S_CLK_CFG,
- SPEAR1310_I2S_REF_SHIFT, SPEAR1310_I2S_REF_SEL_MASK, 0,
- &_lock);
- clk_register_clkdev(clk, "i2s_ref_clk", NULL);
+ ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_REF_SHIFT,
+ SPEAR1310_I2S_REF_SEL_MASK, 0, &_lock);
+ clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0,
SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_I2S_REF_PAD_CLK_ENB,
@@ -664,7 +680,7 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL);
clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk",
- "i2s_ref_pad_clk", 0, SPEAR1310_I2S_CLK_CFG,
+ "i2s_ref_mclk", 0, SPEAR1310_I2S_CLK_CFG,
&i2s_sclk_masks, i2s_sclk_rtbl,
ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1);
clk_register_clkdev(clk, "i2s_sclk_clk", NULL);
@@ -705,35 +721,37 @@ void __init spear1310_clk_init(void)
clk = clk_register_gate(NULL, "usbh0_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UHC0_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.0_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e4000000.ohci");
+ clk_register_clkdev(clk, NULL, "e4800000.ehci");
clk = clk_register_gate(NULL, "usbh1_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UHC1_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.1_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e5000000.ohci");
+ clk_register_clkdev(clk, NULL, "e5800000.ehci");
clk = clk_register_gate(NULL, "uoc_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UOC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "uoc");
+ clk_register_clkdev(clk, NULL, "e3800000.otg");
clk = clk_register_gate(NULL, "pcie_sata_0_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_0_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie.0");
- clk_register_clkdev(clk, NULL, "ahci.0");
+ clk_register_clkdev(clk, NULL, "b1000000.ahci");
clk = clk_register_gate(NULL, "pcie_sata_1_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_1_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie.1");
- clk_register_clkdev(clk, NULL, "ahci.1");
+ clk_register_clkdev(clk, NULL, "b1800000.ahci");
clk = clk_register_gate(NULL, "pcie_sata_2_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_2_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie.2");
- clk_register_clkdev(clk, NULL, "ahci.2");
+ clk_register_clkdev(clk, NULL, "b4000000.ahci");
clk = clk_register_gate(NULL, "sysram0_clk", "ahb_clk", 0,
SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SYSRAM0_CLK_ENB, 0,
@@ -751,10 +769,10 @@ void __init spear1310_clk_init(void)
clk_register_clkdev(clk, "adc_syn_clk", NULL);
clk_register_clkdev(clk1, "adc_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0,
- SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_ADC_CLK_ENB, 0,
- &_lock);
- clk_register_clkdev(clk, NULL, "adc_clk");
+ clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB,
+ SPEAR1310_ADC_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "e0080000.adc");
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0,
@@ -916,15 +934,15 @@ void __init spear1310_clk_init(void)
SPEAR1310_RAS_CTRL_REG1,
SPEAR1310_SMII_RGMII_PHY_CLK_SHIFT,
SPEAR1310_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.1");
- clk_register_clkdev(clk, NULL, "stmmacphy.2");
- clk_register_clkdev(clk, NULL, "stmmacphy.4");
+ clk_register_clkdev(clk, "stmmacphy.1", NULL);
+ clk_register_clkdev(clk, "stmmacphy.2", NULL);
+ clk_register_clkdev(clk, "stmmacphy.4", NULL);
clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents,
ARRAY_SIZE(rmii_phy_parents), 0,
SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT,
SPEAR1310_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.3");
+ clk_register_clkdev(clk, "stmmacphy.3", NULL);
clk = clk_register_mux(NULL, "uart1_mclk", uart_parents,
ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c
index 2352cee7f645..82abea366b78 100644
--- a/drivers/clk/spear/spear1340_clock.c
+++ b/drivers/clk/spear/spear1340_clock.c
@@ -190,6 +190,7 @@ static struct pll_rate_tbl pll4_rtbl[] = {
* different values of vco1div2
*/
static struct frac_rate_tbl amba_synth_rtbl[] = {
+ {.div = 0x073A8}, /* for vco1div2 = 600 MHz */
{.div = 0x06062}, /* for vco1div2 = 500 MHz */
{.div = 0x04D1B}, /* for vco1div2 = 400 MHz */
{.div = 0x04000}, /* for vco1div2 = 332 MHz */
@@ -220,6 +221,12 @@ static struct frac_rate_tbl amba_synth_rtbl[] = {
* 500 400 200 0x02800
* 500 500 250 0x02000
* --------------------------------------------------------------------
+ * 600 200 100 0x06000
+ * 600 250 125 0x04CCE
+ * 600 332 166 0x039D5
+ * 600 400 200 0x03000
+ * 600 500 250 0x02666
+ * --------------------------------------------------------------------
* 664 200 100 0x06a38
* 664 250 125 0x054FD
* 664 332 166 0x04000
@@ -238,28 +245,50 @@ static struct frac_rate_tbl sys_synth_rtbl[] = {
{.div = 0x08000},
{.div = 0x06a38},
{.div = 0x06666},
+ {.div = 0x06000},
{.div = 0x054FD},
{.div = 0x05000},
{.div = 0x04D18},
+ {.div = 0x04CCE},
{.div = 0x04000},
+ {.div = 0x039D5},
{.div = 0x0351E},
{.div = 0x03333},
{.div = 0x03031},
+ {.div = 0x03000},
{.div = 0x02A7E},
{.div = 0x02800},
{.div = 0x0268D},
+ {.div = 0x02666},
{.div = 0x02000},
};
/* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = {
- /* For VCO1div2 = 500 MHz */
- {.xscale = 10, .yscale = 204, .eq = 0}, /* 12.29 MHz */
- {.xscale = 4, .yscale = 21, .eq = 0}, /* 48 MHz */
- {.xscale = 2, .yscale = 6, .eq = 0}, /* 83 MHz */
- {.xscale = 2, .yscale = 4, .eq = 0}, /* 125 MHz */
- {.xscale = 1, .yscale = 3, .eq = 1}, /* 166 MHz */
- {.xscale = 1, .yscale = 2, .eq = 1}, /* 250 MHz */
+ /* 12.29MHz for vic1div2=600MHz and 10.24MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 122, .eq = 0},
+ /* 14.70MHz for vic1div2=600MHz and 12.29MHz for VCO1div2=500MHz */
+ {.xscale = 10, .yscale = 204, .eq = 0},
+ /* 48MHz for vic1div2=600MHz and 40 MHz for VCO1div2=500MHz */
+ {.xscale = 4, .yscale = 25, .eq = 0},
+ /* 57.14MHz for vic1div2=600MHz and 48 MHz for VCO1div2=500MHz */
+ {.xscale = 4, .yscale = 21, .eq = 0},
+ /* 83.33MHz for vic1div2=600MHz and 69.44MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 18, .eq = 0},
+ /* 100MHz for vic1div2=600MHz and 83.33 MHz for VCO1div2=500MHz */
+ {.xscale = 2, .yscale = 6, .eq = 0},
+ /* 125MHz for vic1div2=600MHz and 104.1MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 12, .eq = 0},
+ /* 150MHz for vic1div2=600MHz and 125MHz for VCO1div2=500MHz */
+ {.xscale = 2, .yscale = 4, .eq = 0},
+ /* 166MHz for vic1div2=600MHz and 138.88MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 18, .eq = 1},
+ /* 200MHz for vic1div2=600MHz and 166MHz for VCO1div2=500MHz */
+ {.xscale = 1, .yscale = 3, .eq = 1},
+ /* 250MHz for vic1div2=600MHz and 208.33MHz for VCO1div2=500MHz */
+ {.xscale = 5, .yscale = 12, .eq = 1},
+ /* 300MHz for vic1div2=600MHz and 250MHz for VCO1div2=500MHz */
+ {.xscale = 1, .yscale = 2, .eq = 1},
};
/* gmac rate configuration table, in ascending order of rates */
@@ -273,16 +302,23 @@ static struct aux_rate_tbl gmac_rtbl[] = {
/* clcd rate configuration table, in ascending order of rates */
static struct frac_rate_tbl clcd_rtbl[] = {
+ {.div = 0x18000}, /* 25 Mhz , for vc01div4 = 300 MHz*/
+ {.div = 0x1638E}, /* 27 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x14000}, /* 25 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x1284B}, /* 27 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x0D8D3}, /* 58 Mhz , for vco1div4 = 393 MHz */
{.div = 0x0B72C}, /* 58 Mhz , for vco1div4 = 332 MHz */
+ {.div = 0x0A584}, /* 58 Mhz , for vco1div4 = 300 MHz */
+ {.div = 0x093B1}, /* 65 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x089EE}, /* 58 Mhz , for vc01div4 = 250 MHz*/
+ {.div = 0x081BA}, /* 74 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x07BA0}, /* 65 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x06f1C}, /* 72 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x06E58}, /* 58 Mhz , for vco1div4 = 200 MHz */
{.div = 0x06c1B}, /* 74 Mhz , for vc01div4 = 250 MHz*/
+ {.div = 0x058E3}, /* 108 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x04A12}, /* 108 Mhz , for vc01div4 = 250 MHz*/
+ {.div = 0x040A5}, /* 148.5 Mhz , for vc01div4 = 300 MHz*/
{.div = 0x0378E}, /* 144 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x0360D}, /* 148 Mhz , for vc01div4 = 250 MHz*/
{.div = 0x035E0}, /* 148.5 MHz, for vc01div4 = 250 MHz*/
@@ -351,26 +387,37 @@ static struct aux_rate_tbl adc_rtbl[] = {
/* General synth rate configuration table, in ascending order of rates */
static struct frac_rate_tbl gen_rtbl[] = {
- /* For vco1div4 = 250 MHz */
- {.div = 0x1624E}, /* 22.5792 MHz */
- {.div = 0x14585}, /* 24.576 MHz */
- {.div = 0x14000}, /* 25 MHz */
- {.div = 0x0B127}, /* 45.1584 MHz */
- {.div = 0x0A000}, /* 50 MHz */
- {.div = 0x061A8}, /* 81.92 MHz */
- {.div = 0x05000}, /* 100 MHz */
- {.div = 0x02800}, /* 200 MHz */
- {.div = 0x02620}, /* 210 MHz */
- {.div = 0x02460}, /* 220 MHz */
- {.div = 0x022C0}, /* 230 MHz */
- {.div = 0x02160}, /* 240 MHz */
- {.div = 0x02000}, /* 250 MHz */
+ {.div = 0x1A92B}, /* 22.5792 MHz for vco1div4=300 MHz*/
+ {.div = 0x186A0}, /* 24.576 MHz for vco1div4=300 MHz*/
+ {.div = 0x18000}, /* 25 MHz for vco1div4=300 MHz*/
+ {.div = 0x1624E}, /* 22.5792 MHz for vco1div4=250 MHz*/
+ {.div = 0x14585}, /* 24.576 MHz for vco1div4=250 MHz*/
+ {.div = 0x14000}, /* 25 MHz for vco1div4=250 MHz*/
+ {.div = 0x0D495}, /* 45.1584 MHz for vco1div4=300 MHz*/
+ {.div = 0x0C000}, /* 50 MHz for vco1div4=300 MHz*/
+ {.div = 0x0B127}, /* 45.1584 MHz for vco1div4=250 MHz*/
+ {.div = 0x0A000}, /* 50 MHz for vco1div4=250 MHz*/
+ {.div = 0x07530}, /* 81.92 MHz for vco1div4=300 MHz*/
+ {.div = 0x061A8}, /* 81.92 MHz for vco1div4=250 MHz*/
+ {.div = 0x06000}, /* 100 MHz for vco1div4=300 MHz*/
+ {.div = 0x05000}, /* 100 MHz for vco1div4=250 MHz*/
+ {.div = 0x03000}, /* 200 MHz for vco1div4=300 MHz*/
+ {.div = 0x02DB6}, /* 210 MHz for vco1div4=300 MHz*/
+ {.div = 0x02BA2}, /* 220 MHz for vco1div4=300 MHz*/
+ {.div = 0x029BD}, /* 230 MHz for vco1div4=300 MHz*/
+ {.div = 0x02800}, /* 200 MHz for vco1div4=250 MHz*/
+ {.div = 0x02666}, /* 250 MHz for vco1div4=300 MHz*/
+ {.div = 0x02620}, /* 210 MHz for vco1div4=250 MHz*/
+ {.div = 0x02460}, /* 220 MHz for vco1div4=250 MHz*/
+ {.div = 0x022C0}, /* 230 MHz for vco1div4=250 MHz*/
+ {.div = 0x02160}, /* 240 MHz for vco1div4=250 MHz*/
+ {.div = 0x02000}, /* 250 MHz for vco1div4=250 MHz*/
};
/* clock parents */
static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", };
static const char *sys_parents[] = { "pll1_clk", "pll1_clk", "pll1_clk",
- "pll1_clk", "sys_synth_clk", "sys_synth_clk", "pll2_clk", "pll3_clk", };
+ "pll1_clk", "sys_syn_clk", "sys_syn_clk", "pll2_clk", "pll3_clk", };
static const char *ahb_parents[] = { "cpu_div3_clk", "amba_syn_clk", };
static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", };
static const char *uart0_parents[] = { "pll5_clk", "osc_24m_clk",
@@ -391,16 +438,13 @@ static const char *spdif_in_parents[] = { "pll2_clk", "gen_syn3_clk", };
static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk",
"pll3_clk", };
-static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco3div2_clk",
+static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco2div2_clk",
"pll2_clk", };
void __init spear1340_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -425,7 +469,7 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_RTC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "fc900000.rtc");
+ clk_register_clkdev(clk, NULL, "e0580000.rtc");
/* clock derived from 24 or 25 MHz osc clk */
/* vco-pll */
@@ -499,7 +543,7 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_THSENS_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_thermal");
+ clk_register_clkdev(clk, NULL, "e07008c4.thermal");
/* clock derived from pll4 clk */
clk = clk_register_fixed_factor(NULL, "ddr_clk", "pll4_clk", 0, 1,
@@ -521,7 +565,7 @@ void __init spear1340_clk_init(void)
ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL,
SPEAR1340_SCLK_SRC_SEL_SHIFT,
SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock);
- clk_register_clkdev(clk, "sys_clk", NULL);
+ clk_register_clkdev(clk, "sys_mclk", NULL);
clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mclk", 0, 1,
2);
@@ -535,6 +579,10 @@ void __init spear1340_clk_init(void)
2);
clk_register_clkdev(clk, NULL, "ec800620.wdt");
+ clk = clk_register_fixed_factor(NULL, "smp_twd_clk", "cpu_clk", 0, 1,
+ 2);
+ clk_register_clkdev(clk, NULL, "smp_twd");
+
clk = clk_register_mux(NULL, "ahb_clk", ahb_parents,
ARRAY_SIZE(ahb_parents), 0, SPEAR1340_SYS_CLK_CTRL,
SPEAR1340_HCLK_SRC_SEL_SHIFT,
@@ -594,14 +642,14 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk1, "uart0_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_UART0_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART0_CLK_SHIFT,
+ SPEAR1340_UART_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
- clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART0_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_UART0_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "e0000000.serial");
clk = clk_register_aux("uart1_syn_clk", "uart1_syn_gclk",
@@ -627,9 +675,9 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "sdhci_syn_clk", NULL);
clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SDHCI_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_SDHCI_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b3000000.sdhci");
clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk",
@@ -638,9 +686,9 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "cfxd_syn_clk", NULL);
clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CFXD_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_CFXD_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "b2800000.cf");
clk_register_clkdev(clk, NULL, "arasan_xd");
@@ -651,15 +699,15 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
- ARRAY_SIZE(c3_parents), 0, SPEAR1340_PERIP_CLK_CFG,
- SPEAR1340_C3_CLK_SHIFT, SPEAR1340_C3_CLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+ SPEAR1340_PERIP_CLK_CFG, SPEAR1340_C3_CLK_SHIFT,
+ SPEAR1340_C3_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "c3_mclk", NULL);
- clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0,
+ clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", CLK_SET_RATE_PARENT,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_C3_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "c3");
+ clk_register_clkdev(clk, NULL, "e1800000.c3");
/* gmac */
clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
@@ -679,7 +727,7 @@ void __init spear1340_clk_init(void)
ARRAY_SIZE(gmac_phy_parents), 0,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT,
SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, NULL, "stmmacphy.0");
+ clk_register_clkdev(clk, "stmmacphy.0", NULL);
/* clcd */
clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
@@ -694,33 +742,34 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "clcd_syn_clk", NULL);
clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
- ARRAY_SIZE(clcd_pixel_parents), 0,
+ ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT,
SPEAR1340_CLCD_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "clcd_pixel_clk", NULL);
+ clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CLCD_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "clcd_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e1000000.clcd");
/* i2s */
clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG,
SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK,
0, &_lock);
- clk_register_clkdev(clk, "i2s_src_clk", NULL);
+ clk_register_clkdev(clk, "i2s_src_mclk", NULL);
- clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
- SPEAR1340_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl,
+ clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_I2S_CLK_CFG,
+ &i2s_prs1_masks, i2s_prs1_rtbl,
ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL);
clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1340_I2S_CLK_CFG,
- SPEAR1340_I2S_REF_SHIFT, SPEAR1340_I2S_REF_SEL_MASK, 0,
- &_lock);
- clk_register_clkdev(clk, "i2s_ref_clk", NULL);
+ ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_REF_SHIFT,
+ SPEAR1340_I2S_REF_SEL_MASK, 0, &_lock);
+ clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_I2S_REF_PAD_CLK_ENB,
@@ -769,23 +818,25 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "usbh0_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UHC0_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.0_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e4000000.ohci");
+ clk_register_clkdev(clk, NULL, "e4800000.ehci");
clk = clk_register_gate(NULL, "usbh1_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UHC1_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, "usbh.1_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e5000000.ohci");
+ clk_register_clkdev(clk, NULL, "e5800000.ehci");
clk = clk_register_gate(NULL, "uoc_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UOC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "uoc");
+ clk_register_clkdev(clk, NULL, "e3800000.otg");
clk = clk_register_gate(NULL, "pcie_sata_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_PCIE_SATA_CLK_ENB,
0, &_lock);
clk_register_clkdev(clk, NULL, "dw_pcie");
- clk_register_clkdev(clk, NULL, "ahci");
+ clk_register_clkdev(clk, NULL, "b1000000.ahci");
clk = clk_register_gate(NULL, "sysram0_clk", "ahb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SYSRAM0_CLK_ENB, 0,
@@ -803,10 +854,10 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, "adc_syn_clk", NULL);
clk_register_clkdev(clk1, "adc_syn_gclk", NULL);
- clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0,
- SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_ADC_CLK_ENB, 0,
- &_lock);
- clk_register_clkdev(clk, NULL, "adc_clk");
+ clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB,
+ SPEAR1340_ADC_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "e0080000.adc");
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "ssp_clk", "apb_clk", 0,
@@ -827,12 +878,12 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "i2s_play_clk", "apb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2S_PLAY_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "b2400000.i2s");
+ clk_register_clkdev(clk, NULL, "b2400000.i2s-play");
clk = clk_register_gate(NULL, "i2s_rec_clk", "apb_clk", 0,
SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2S_REC_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "b2000000.i2s");
+ clk_register_clkdev(clk, NULL, "b2000000.i2s-rec");
clk = clk_register_gate(NULL, "kbd_clk", "apb_clk", 0,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_KBD_CLK_ENB, 0,
@@ -844,37 +895,37 @@ void __init spear1340_clk_init(void)
ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG,
SPEAR1340_GEN_SYNT0_1_CLK_SHIFT,
SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "gen_syn0_1_clk", NULL);
+ clk_register_clkdev(clk, "gen_syn0_1_mclk", NULL);
clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG,
SPEAR1340_GEN_SYNT2_3_CLK_SHIFT,
SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
- clk_register_clkdev(clk, "gen_syn2_3_clk", NULL);
+ clk_register_clkdev(clk, "gen_syn2_3_mclk", NULL);
- clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0,
+ clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_mclk", 0,
SPEAR1340_GEN_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn0_clk", NULL);
- clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0,
+ clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_mclk", 0,
SPEAR1340_GEN_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn1_clk", NULL);
- clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0,
+ clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_mclk", 0,
SPEAR1340_GEN_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn2_clk", NULL);
- clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0,
+ clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_mclk", 0,
SPEAR1340_GEN_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl),
&_lock);
clk_register_clkdev(clk, "gen_syn3_clk", NULL);
- clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk", 0,
- SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_MALI_CLK_ENB, 0,
- &_lock);
+ clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB,
+ SPEAR1340_MALI_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, NULL, "mali");
clk = clk_register_gate(NULL, "cec0_clk", "ahb_clk", 0,
@@ -888,26 +939,26 @@ void __init spear1340_clk_init(void)
clk_register_clkdev(clk, NULL, "spear_cec.1");
clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents,
- ARRAY_SIZE(spdif_out_parents), 0,
+ ARRAY_SIZE(spdif_out_parents), CLK_SET_RATE_PARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT,
SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "spdif_out_mclk", NULL);
- clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk", 0,
- SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_OUT_CLK_ENB,
- 0, &_lock);
- clk_register_clkdev(clk, NULL, "spdif-out");
+ clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB,
+ SPEAR1340_SPDIF_OUT_CLK_ENB, 0, &_lock);
+ clk_register_clkdev(clk, NULL, "d0000000.spdif-out");
clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents,
- ARRAY_SIZE(spdif_in_parents), 0,
+ ARRAY_SIZE(spdif_in_parents), CLK_SET_RATE_PARENT,
SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT,
SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "spdif_in_mclk", NULL);
- clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk", 0,
- SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_IN_CLK_ENB, 0,
- &_lock);
- clk_register_clkdev(clk, NULL, "spdif-in");
+ clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk",
+ CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB,
+ 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,
SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0,
@@ -917,7 +968,7 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "plgpio");
+ clk_register_clkdev(clk, NULL, "e2800000.gpio");
clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB,
@@ -937,25 +988,25 @@ void __init spear1340_clk_init(void)
clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.0");
+ clk_register_clkdev(clk, NULL, "d0200000.cam0");
clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.1");
+ clk_register_clkdev(clk, NULL, "d0300000.cam1");
clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.2");
+ clk_register_clkdev(clk, NULL, "d0400000.cam2");
clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "spear_camif.3");
+ clk_register_clkdev(clk, NULL, "d0500000.cam3");
- clk = clk_register_gate(NULL, "pwm_clk", "pwm_mclk", 0,
+ clk = clk_register_gate(NULL, "pwm_clk", "ahb_clk", 0,
SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PWM_CLK_ENB, 0,
&_lock);
- clk_register_clkdev(clk, NULL, "pwm");
+ clk_register_clkdev(clk, NULL, "e0180000.pwm");
}
diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c
index c3157454bb3f..33d3ac588da7 100644
--- a/drivers/clk/spear/spear3xx_clock.c
+++ b/drivers/clk/spear/spear3xx_clock.c
@@ -107,6 +107,12 @@ static struct pll_rate_tbl pll_rtbl[] = {
/* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = {
/* For PLL1 = 332 MHz */
+ {.xscale = 1, .yscale = 81, .eq = 0}, /* 2.049 MHz */
+ {.xscale = 1, .yscale = 59, .eq = 0}, /* 2.822 MHz */
+ {.xscale = 2, .yscale = 81, .eq = 0}, /* 4.098 MHz */
+ {.xscale = 3, .yscale = 89, .eq = 0}, /* 5.644 MHz */
+ {.xscale = 4, .yscale = 81, .eq = 0}, /* 8.197 MHz */
+ {.xscale = 4, .yscale = 59, .eq = 0}, /* 11.254 MHz */
{.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */
{.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */
{.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */
@@ -157,6 +163,8 @@ static void __init spear300_clk_init(void)
1);
clk_register_clkdev(clk, NULL, "a0000000.kbd");
}
+#else
+static inline void spear300_clk_init(void) { }
#endif
/* array of all spear 310 clock lookups */
@@ -197,6 +205,8 @@ static void __init spear310_clk_init(void)
1);
clk_register_clkdev(clk, NULL, "b2200000.serial");
}
+#else
+static inline void spear310_clk_init(void) { }
#endif
/* array of all spear 320 clock lookups */
@@ -251,7 +261,7 @@ static void __init spear320_clk_init(void)
clk = clk_register_fixed_factor(NULL, "pwm_clk", "ras_ahb_clk", 0, 1,
1);
- clk_register_clkdev(clk, "pwm", NULL);
+ clk_register_clkdev(clk, NULL, "a8000000.pwm");
clk = clk_register_fixed_factor(NULL, "ssp1_clk", "ras_ahb_clk", 0, 1,
1);
@@ -271,26 +281,37 @@ static void __init spear320_clk_init(void)
clk = clk_register_fixed_factor(NULL, "i2s_clk", "ras_apb_clk", 0, 1,
1);
- clk_register_clkdev(clk, NULL, "i2s");
+ clk_register_clkdev(clk, NULL, "a9400000.i2s");
clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents,
- ARRAY_SIZE(i2s_ref_parents), 0, SPEAR320_CONTROL_REG,
- I2S_REF_PCLK_SHIFT, I2S_REF_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_CONTROL_REG, I2S_REF_PCLK_SHIFT,
+ I2S_REF_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "i2s_ref_clk", NULL);
- clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", 0, 1,
+ clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk",
+ CLK_SET_RATE_PARENT, 1,
4);
clk_register_clkdev(clk, "i2s_sclk", NULL);
+ clk = clk_register_fixed_factor(NULL, "macb1_clk", "ras_apb_clk", 0, 1,
+ 1);
+ clk_register_clkdev(clk, "hclk", "aa000000.eth");
+
+ clk = clk_register_fixed_factor(NULL, "macb2_clk", "ras_apb_clk", 0, 1,
+ 1);
+ clk_register_clkdev(clk, "hclk", "ab000000.eth");
+
clk = clk_register_mux(NULL, "rs485_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_RS485_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_RS485_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9300000.serial");
clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents,
- ARRAY_SIZE(sdhci_parents), 0, SPEAR320_CONTROL_REG,
- SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(sdhci_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_CONTROL_REG, SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK,
+ 0, &_lock);
clk_register_clkdev(clk, NULL, "70000000.sdhci");
clk = clk_register_mux(NULL, "smii_pclk", smii0_parents,
@@ -302,49 +323,49 @@ static void __init spear320_clk_init(void)
clk_register_clkdev(clk, NULL, "smii");
clk = clk_register_mux(NULL, "uart1_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_CONTROL_REG,
- UART1_PCLK_SHIFT, UART1_PCLK_MASK, 0, &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_CONTROL_REG, UART1_PCLK_SHIFT, UART1_PCLK_MASK,
+ 0, &_lock);
clk_register_clkdev(clk, NULL, "a3000000.serial");
clk = clk_register_mux(NULL, "uart2_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART2_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART2_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a4000000.serial");
clk = clk_register_mux(NULL, "uart3_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART3_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART3_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9100000.serial");
clk = clk_register_mux(NULL, "uart4_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART4_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART4_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "a9200000.serial");
clk = clk_register_mux(NULL, "uart5_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART5_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART5_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "60000000.serial");
clk = clk_register_mux(NULL, "uart6_clk", uartx_parents,
- ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG,
- SPEAR320_UART6_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0,
- &_lock);
+ ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+ SPEAR320_EXT_CTRL_REG, SPEAR320_UART6_PCLK_SHIFT,
+ SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "60100000.serial");
}
+#else
+static inline void spear320_clk_init(void) { }
#endif
void __init spear3xx_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -380,7 +401,8 @@ void __init spear3xx_clk_init(void)
clk_register_clkdev(clk1, "pll2_clk", NULL);
/* clock derived from pll1 clk */
- clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1);
+ clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
+ CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk",
@@ -395,12 +417,14 @@ void __init spear3xx_clk_init(void)
clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
- ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG,
- UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "uart0_mclk", NULL);
- clk = clk_register_gate(NULL, "uart0", "uart0_mclk", 0, PERIP1_CLK_ENB,
- UART_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "uart0", "uart0_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, UART_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "d0000000.serial");
clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk", 0,
@@ -410,40 +434,44 @@ void __init spear3xx_clk_init(void)
clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
- ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG,
- FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(firda_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0,
+ &_lock);
clk_register_clkdev(clk, "firda_mclk", NULL);
- clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0,
- PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "firda_clk", "firda_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "firda");
/* gpt clocks */
clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents,
- ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG,
- GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt0_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, NULL, "gpt0");
clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents,
- ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG,
- GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt1_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt1_mclk", NULL);
- clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
- PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, GPT1_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "gpt1");
clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl,
ARRAY_SIZE(gpt_rtbl), &_lock);
clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
- ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG,
- GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+ ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_PARENT,
+ PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
clk_register_clkdev(clk, "gpt2_mclk", NULL);
- clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
- PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk",
+ CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, GPT2_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, NULL, "gpt2");
/* general synths clocks */
@@ -480,7 +508,9 @@ void __init spear3xx_clk_init(void)
/* clock derived from pll3 clk */
clk = clk_register_gate(NULL, "usbh_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBH_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, "usbh_clk", NULL);
+ clk_register_clkdev(clk, NULL, "e1800000.ehci");
+ clk_register_clkdev(clk, NULL, "e1900000.ohci");
+ clk_register_clkdev(clk, NULL, "e2100000.ohci");
clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1,
1);
@@ -492,7 +522,7 @@ void __init spear3xx_clk_init(void)
clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBD_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "designware_udc");
+ clk_register_clkdev(clk, NULL, "e1100000.usbd");
/* clock derived from ahb clk */
clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2,
@@ -540,7 +570,7 @@ void __init spear3xx_clk_init(void)
/* clock derived from apb clk */
clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB,
ADC_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "adc");
+ clk_register_clkdev(clk, NULL, "d0080000.adc");
clk = clk_register_gate(NULL, "gpio0_clk", "apb_clk", 0, PERIP1_CLK_ENB,
GPIO_CLK_ENB, 0, &_lock);
@@ -579,20 +609,24 @@ void __init spear3xx_clk_init(void)
RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock);
clk_register_clkdev(clk, "ras_pll3_clk", NULL);
- clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn0_gclk", NULL);
- clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn1_gclk", NULL);
- clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn2_gclk", NULL);
- clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk", 0,
- RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0, &_lock);
+ clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk",
+ CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0,
+ &_lock);
clk_register_clkdev(clk, "ras_syn3_gclk", NULL);
if (of_machine_is_compatible("st,spear300"))
diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c
index a98d0866f541..e862a333ad30 100644
--- a/drivers/clk/spear/spear6xx_clock.c
+++ b/drivers/clk/spear/spear6xx_clock.c
@@ -92,6 +92,7 @@ static struct pll_rate_tbl pll_rtbl[] = {
/* aux rate configuration table, in ascending order of rates */
static struct aux_rate_tbl aux_rtbl[] = {
/* For PLL1 = 332 MHz */
+ {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */
{.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */
{.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */
{.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */
@@ -118,9 +119,6 @@ void __init spear6xx_clk_init(void)
{
struct clk *clk, *clk1;
- clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
- clk_register_clkdev(clk, "apb_pclk", NULL);
-
clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT,
32000);
clk_register_clkdev(clk, "osc_32k_clk", NULL);
@@ -156,7 +154,8 @@ void __init spear6xx_clk_init(void)
clk_register_clkdev(clk, NULL, "wdt");
/* clock derived from pll1 clk */
- clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1);
+ clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk",
+ CLK_SET_RATE_PARENT, 1, 1);
clk_register_clkdev(clk, "cpu_clk", NULL);
clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk",
@@ -261,11 +260,13 @@ void __init spear6xx_clk_init(void)
/* clock derived from pll3 clk */
clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0,
PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "usbh.0_clk");
+ clk_register_clkdev(clk, NULL, "e1800000.ehci");
+ clk_register_clkdev(clk, NULL, "e1900000.ohci");
clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0,
PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock);
- clk_register_clkdev(clk, NULL, "usbh.1_clk");
+ clk_register_clkdev(clk, NULL, "e2000000.ehci");
+ clk_register_clkdev(clk, NULL, "e2100000.ohci");
clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB,
USBD_CLK_ENB, 0, &_lock);
diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile
index 858fbfe66281..bcc0c11a507c 100644
--- a/drivers/clk/ux500/Makefile
+++ b/drivers/clk/ux500/Makefile
@@ -10,3 +10,6 @@ obj-y += clk-prcmu.o
obj-y += u8500_clk.o
obj-y += u9540_clk.o
obj-y += u8540_clk.o
+
+# ABX500 clock driver
+obj-y += abx500-clk.o
diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c
new file mode 100644
index 000000000000..e27c52317ffe
--- /dev/null
+++ b/drivers/clk/ux500/abx500-clk.c
@@ -0,0 +1,73 @@
+/*
+ * abx500 clock implementation for ux500 platform.
+ *
+ * Copyright (C) 2012 ST-Ericsson SA
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/abx500/ab8500.h>
+
+/* TODO: Add clock implementations here */
+
+
+/* Clock definitions for ab8500 */
+static int ab8500_reg_clks(struct device *dev)
+{
+ return 0;
+}
+
+/* Clock definitions for ab8540 */
+static int ab8540_reg_clks(struct device *dev)
+{
+ return 0;
+}
+
+/* Clock definitions for ab9540 */
+static int ab9540_reg_clks(struct device *dev)
+{
+ return 0;
+}
+
+static int __devinit abx500_clk_probe(struct platform_device *pdev)
+{
+ struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ if (is_ab8500(parent) || is_ab8505(parent)) {
+ ret = ab8500_reg_clks(&pdev->dev);
+ } else if (is_ab8540(parent)) {
+ ret = ab8540_reg_clks(&pdev->dev);
+ } else if (is_ab9540(parent)) {
+ ret = ab9540_reg_clks(&pdev->dev);
+ } else {
+ dev_err(&pdev->dev, "non supported plf id\n");
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static struct platform_driver abx500_clk_driver = {
+ .driver = {
+ .name = "abx500-clk",
+ .owner = THIS_MODULE,
+ },
+ .probe = abx500_clk_probe,
+};
+
+static int __init abx500_clk_init(void)
+{
+ return platform_driver_register(&abx500_clk_driver);
+}
+
+arch_initcall(abx500_clk_init);
+
+MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org");
+MODULE_DESCRIPTION("ABX500 clk driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index 930cdfeb47ab..74faa7e3cf59 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -133,6 +133,40 @@ out_error:
hw->init->name);
}
+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;
+ }
+
+ err = prcmu_request_clock(clk->cg_sel, true);
+ if (err)
+ prcmu_request_ape_opp_100_voltage(false);
+
+ return err;
+}
+
+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);
+}
+
static struct clk_ops clk_prcmu_scalable_ops = {
.prepare = clk_prcmu_prepare,
.unprepare = clk_prcmu_unprepare,
@@ -153,6 +187,13 @@ static struct clk_ops clk_prcmu_gate_ops = {
.recalc_rate = clk_prcmu_recalc_rate,
};
+static struct clk_ops clk_prcmu_scalable_rate_ops = {
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+ .round_rate = clk_prcmu_round_rate,
+ .set_rate = clk_prcmu_set_rate,
+};
+
static struct clk_ops clk_prcmu_rate_ops = {
.is_enabled = clk_prcmu_is_enabled,
.recalc_rate = clk_prcmu_recalc_rate,
@@ -167,6 +208,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = {
.recalc_rate = clk_prcmu_recalc_rate,
};
+static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
+ .prepare = clk_prcmu_opp_volt_prepare,
+ .unprepare = clk_prcmu_opp_volt_unprepare,
+ .enable = clk_prcmu_enable,
+ .disable = clk_prcmu_disable,
+ .is_enabled = clk_prcmu_is_enabled,
+ .recalc_rate = clk_prcmu_recalc_rate,
+ .round_rate = clk_prcmu_round_rate,
+ .set_rate = clk_prcmu_set_rate,
+};
+
static struct clk *clk_reg_prcmu(const char *name,
const char *parent_name,
u8 cg_sel,
@@ -233,6 +285,16 @@ struct clk *clk_reg_prcmu_gate(const char *name,
&clk_prcmu_gate_ops);
}
+struct clk *clk_reg_prcmu_scalable_rate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+ &clk_prcmu_scalable_rate_ops);
+}
+
struct clk *clk_reg_prcmu_rate(const char *name,
const char *parent_name,
u8 cg_sel,
@@ -250,3 +312,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
&clk_prcmu_opp_gate_ops);
}
+
+struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags)
+{
+ return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
+ &clk_prcmu_opp_volt_scalable_ops);
+}
diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h
index 836d7d16751e..c3e449169a83 100644
--- a/drivers/clk/ux500/clk.h
+++ b/drivers/clk/ux500/clk.h
@@ -35,6 +35,12 @@ struct clk *clk_reg_prcmu_gate(const char *name,
u8 cg_sel,
unsigned long flags);
+struct clk *clk_reg_prcmu_scalable_rate(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags);
+
struct clk *clk_reg_prcmu_rate(const char *name,
const char *parent_name,
u8 cg_sel,
@@ -45,4 +51,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name,
u8 cg_sel,
unsigned long flags);
+struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
+ const char *parent_name,
+ u8 cg_sel,
+ unsigned long rate,
+ unsigned long flags);
+
#endif /* __UX500_CLK_H */
diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c
index ca4a25ed844c..7d0e0258f204 100644
--- a/drivers/clk/ux500/u8500_clk.c
+++ b/drivers/clk/ux500/u8500_clk.c
@@ -40,7 +40,7 @@ void u8500_clk_init(void)
CLK_IS_ROOT|CLK_IGNORE_UNUSED,
32768);
clk_register_clkdev(clk, "clk32k", NULL);
- clk_register_clkdev(clk, NULL, "rtc-pl031");
+ clk_register_clkdev(clk, "apb_pclk", "rtc-pl031");
/* PRCMU clocks */
fw_version = prcmu_get_fw_version();
@@ -170,10 +170,11 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, NULL, "mtu0");
clk_register_clkdev(clk, NULL, "mtu1");
- clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT);
+ clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK,
+ 100000000,
+ CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdmmc");
-
clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs2", "mcde");
@@ -205,16 +206,18 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, "dsilp2", "dsilink.2");
clk_register_clkdev(clk, "dsilp2", "mcde");
- clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS,
- CLK_IS_ROOT|CLK_GET_RATE_NOCACHE|
- CLK_IGNORE_UNUSED);
+ clk = clk_reg_prcmu_scalable_rate("armss", NULL,
+ PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
+ clk_register_clkdev(clk, "armss", NULL);
+
+ clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
+ CLK_IGNORE_UNUSED, 1, 2);
clk_register_clkdev(clk, NULL, "smp_twd");
/*
* FIXME: Add special handled PRCMU clocks here:
- * 1. clk_arm, use PRCMU_ARMCLK.
- * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
- * 3. ab9540_clkout1yuv, see clkout0yuv
+ * 1. clkout0yuv, use PRCMU as parent + need regulator + pinctrl.
+ * 2. ab9540_clkout1yuv, see clkout0yuv
*/
/* PRCC P-clocks */
@@ -228,10 +231,17 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", U8500_CLKRST1_BASE,
BIT(2), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1");
+
clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", U8500_CLKRST1_BASE,
BIT(3), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp0");
+ clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.0");
+
clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", U8500_CLKRST1_BASE,
BIT(4), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp1");
+ clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.1");
clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", U8500_CLKRST1_BASE,
BIT(5), 0);
@@ -239,6 +249,7 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", U8500_CLKRST1_BASE,
BIT(6), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2");
clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", U8500_CLKRST1_BASE,
BIT(7), 0);
@@ -246,6 +257,7 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", U8500_CLKRST1_BASE,
BIT(8), 0);
+ clk_register_clkdev(clk, "apb_pclk", "slimbus0");
clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", U8500_CLKRST1_BASE,
BIT(9), 0);
@@ -255,11 +267,16 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", U8500_CLKRST1_BASE,
BIT(10), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4");
+
clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", U8500_CLKRST1_BASE,
BIT(11), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp3");
+ clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.3");
clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", U8500_CLKRST2_BASE,
BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3");
clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", U8500_CLKRST2_BASE,
BIT(1), 0);
@@ -279,12 +296,13 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", U8500_CLKRST2_BASE,
BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "msp2");
+ clk_register_clkdev(clk, "apb_pclk", "ux500-msp-i2s.2");
clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", U8500_CLKRST2_BASE,
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi1");
-
clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", U8500_CLKRST2_BASE,
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi3");
@@ -308,7 +326,7 @@ void u8500_clk_init(void)
clk_register_clkdev(clk, NULL, "gpioblock1");
clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE,
- BIT(11), 0);
+ BIT(12), 0);
clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE,
BIT(0), 0);
@@ -316,10 +334,15 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", U8500_CLKRST3_BASE,
BIT(1), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ssp0");
+
clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", U8500_CLKRST3_BASE,
BIT(2), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ssp1");
+
clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", U8500_CLKRST3_BASE,
BIT(3), 0);
+ clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0");
clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", U8500_CLKRST3_BASE,
BIT(4), 0);
@@ -327,6 +350,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE,
BIT(5), 0);
+ clk_register_clkdev(clk, "apb_pclk", "ske");
+ clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE,
BIT(6), 0);
@@ -355,6 +380,7 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE,
BIT(0), 0);
+ clk_register_clkdev(clk, "apb_pclk", "rng");
clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE,
BIT(1), 0);
@@ -401,10 +427,17 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
U8500_CLKRST1_BASE, BIT(2), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.1");
+
clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp0");
+ clk_register_clkdev(clk, NULL, "ux500-msp-i2s.0");
+
clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
U8500_CLKRST1_BASE, BIT(4), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp1");
+ clk_register_clkdev(clk, NULL, "ux500-msp-i2s.1");
clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmcclk",
U8500_CLKRST1_BASE, BIT(5), CLK_SET_RATE_GATE);
@@ -412,17 +445,25 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
U8500_CLKRST1_BASE, BIT(6), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.2");
+
clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
- U8500_CLKRST1_BASE, BIT(3), CLK_SET_RATE_GATE);
- /* FIXME: Redefinition of BIT(3). */
+ U8500_CLKRST1_BASE, BIT(8), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "slimbus0");
+
clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
U8500_CLKRST1_BASE, BIT(9), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.4");
+
clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
U8500_CLKRST1_BASE, BIT(10), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp3");
+ clk_register_clkdev(clk, NULL, "ux500-msp-i2s.3");
/* Periph2 */
clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
U8500_CLKRST2_BASE, BIT(0), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.3");
clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmcclk",
U8500_CLKRST2_BASE, BIT(2), CLK_SET_RATE_GATE);
@@ -430,6 +471,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
U8500_CLKRST2_BASE, BIT(3), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "msp2");
+ clk_register_clkdev(clk, NULL, "ux500-msp-i2s.2");
clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmcclk",
U8500_CLKRST2_BASE, BIT(4), CLK_SET_RATE_GATE);
@@ -450,10 +493,15 @@ void u8500_clk_init(void)
/* Periph3 */
clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
U8500_CLKRST3_BASE, BIT(1), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ssp0");
+
clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
U8500_CLKRST3_BASE, BIT(2), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ssp1");
+
clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
U8500_CLKRST3_BASE, BIT(3), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "nmk-i2c.0");
clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmcclk",
U8500_CLKRST3_BASE, BIT(4), CLK_SET_RATE_GATE);
@@ -461,6 +509,8 @@ void u8500_clk_init(void)
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE);
+ clk_register_clkdev(clk, NULL, "ske");
+ clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE);
@@ -473,5 +523,5 @@ void u8500_clk_init(void)
/* Periph6 */
clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk",
U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE);
-
+ clk_register_clkdev(clk, NULL, "rng");
}
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index c0a0f6478798..ec3b88fe3e6d 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -1,4 +1,7 @@
# Makefile for Versatile-specific clocks
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_VEXPRESS_CONFIG) += clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c
index f555b50a5fa5..67ccf4aa7277 100644
--- a/drivers/clk/versatile/clk-icst.c
+++ b/drivers/clk/versatile/clk-icst.c
@@ -3,6 +3,12 @@
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
* clock framework.
*
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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: when all ARM reference designs are migrated to generic clocks, the
* ICST clock code from the ARM tree should probably be merged into this
* file.
@@ -11,33 +17,74 @@
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
+#include <linux/io.h>
#include "clk-icst.h"
/**
* struct clk_icst - ICST VCO clock wrapper
* @hw: corresponding clock hardware entry
+ * @vcoreg: VCO register address
+ * @lockreg: VCO lock register address
* @params: parameters for this ICST instance
* @rate: current rate
- * @setvco: function to commit ICST settings to hardware
*/
struct clk_icst {
struct clk_hw hw;
+ void __iomem *vcoreg;
+ void __iomem *lockreg;
const struct icst_params *params;
unsigned long rate;
- struct icst_vco (*getvco)(void);
- void (*setvco)(struct icst_vco);
};
#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
+/**
+ * vco_get() - get ICST VCO settings from a certain register
+ * @vcoreg: register containing the VCO settings
+ */
+static struct icst_vco vco_get(void __iomem *vcoreg)
+{
+ u32 val;
+ struct icst_vco vco;
+
+ val = readl(vcoreg);
+ vco.v = val & 0x1ff;
+ vco.r = (val >> 9) & 0x7f;
+ vco.s = (val >> 16) & 03;
+ return vco;
+}
+
+/**
+ * vco_set() - commit changes to an ICST VCO
+ * @locreg: register to poke to unlock the VCO for writing
+ * @vcoreg: register containing the VCO settings
+ * @vco: ICST VCO parameters to commit
+ */
+static void vco_set(void __iomem *lockreg,
+ void __iomem *vcoreg,
+ struct icst_vco vco)
+{
+ u32 val;
+
+ val = readl(vcoreg) & ~0x7ffff;
+ val |= vco.v | (vco.r << 9) | (vco.s << 16);
+
+ /* This magic unlocks the VCO so it can be controlled */
+ writel(0xa05f, lockreg);
+ writel(val, vcoreg);
+ /* This locks the VCO again */
+ writel(0, lockreg);
+}
+
+
static unsigned long icst_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;
- vco = icst->getvco();
+ vco = vco_get(icst->vcoreg);
icst->rate = icst_hz(icst->params, vco);
return icst->rate;
}
@@ -60,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco);
- icst->setvco(vco);
+ vco_set(icst->vcoreg, icst->lockreg, vco);
return 0;
}
@@ -70,8 +117,9 @@ static const struct clk_ops icst_ops = {
.set_rate = icst_set_rate,
};
-struct clk * __init icst_clk_register(struct device *dev,
- const struct clk_icst_desc *desc)
+struct clk *icst_clk_register(struct device *dev,
+ const struct clk_icst_desc *desc,
+ void __iomem *base)
{
struct clk *clk;
struct clk_icst *icst;
@@ -89,8 +137,8 @@ struct clk * __init icst_clk_register(struct device *dev,
init.num_parents = 0;
icst->hw.init = &init;
icst->params = desc->params;
- icst->getvco = desc->getvco;
- icst->setvco = desc->setvco;
+ icst->vcoreg = base + desc->vco_offset;
+ icst->lockreg = base + desc->lock_offset;
clk = clk_register(dev, &icst->hw);
if (IS_ERR(clk))
diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h
index 71b4c56c1410..dad51b6ffd00 100644
--- a/drivers/clk/versatile/clk-icst.h
+++ b/drivers/clk/versatile/clk-icst.h
@@ -1,10 +1,18 @@
#include <asm/hardware/icst.h>
+/**
+ * struct clk_icst_desc - descriptor for the ICST VCO
+ * @params: ICST parameters
+ * @vco_offset: offset to the ICST VCO from the provided memory base
+ * @lock_offset: offset to the ICST VCO locking register from the provided
+ * memory base
+ */
struct clk_icst_desc {
const struct icst_params *params;
- struct icst_vco (*getvco)(void);
- void (*setvco)(struct icst_vco);
+ u32 vco_offset;
+ u32 lock_offset;
};
struct clk *icst_clk_register(struct device *dev,
- const struct clk_icst_desc *desc);
+ const struct clk_icst_desc *desc,
+ void __iomem *base);
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c
new file mode 100644
index 000000000000..369139af2a3b
--- /dev/null
+++ b/drivers/clk/versatile/clk-impd1.c
@@ -0,0 +1,97 @@
+/*
+ * Clock driver for the ARM Integrator/IM-PD1 board
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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-provider.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_data/clk-integrator.h>
+
+#include <mach/impd1.h>
+
+#include "clk-icst.h"
+
+struct impd1_clk {
+ struct clk *vcoclk;
+ struct clk *uartclk;
+ struct clk_lookup *clks[3];
+};
+
+static struct impd1_clk impd1_clks[4];
+
+/*
+ * There are two VCO's on the IM-PD1 but only one is used by the
+ * kernel, that is why we are only implementing the control of
+ * IMPD1_OSC1 here.
+ */
+
+static const struct icst_params impd1_vco_params = {
+ .ref = 24000000, /* 24 MHz */
+ .vco_max = ICST525_VCO_MAX_3V,
+ .vco_min = ICST525_VCO_MIN,
+ .vd_min = 12,
+ .vd_max = 519,
+ .rd_min = 3,
+ .rd_max = 120,
+ .s2div = icst525_s2div,
+ .idx2s = icst525_idx2s,
+};
+
+static const struct clk_icst_desc impd1_icst1_desc = {
+ .params = &impd1_vco_params,
+ .vco_offset = IMPD1_OSC1,
+ .lock_offset = IMPD1_LOCK,
+};
+
+/**
+ * integrator_impd1_clk_init() - set up the integrator clock tree
+ * @base: base address of the logic module (LM)
+ * @id: the ID of this LM
+ */
+void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
+{
+ struct impd1_clk *imc;
+ struct clk *clk;
+ int i;
+
+ if (id > 3) {
+ pr_crit("no more than 4 LMs can be attached\n");
+ return;
+ }
+ imc = &impd1_clks[id];
+
+ clk = icst_clk_register(NULL, &impd1_icst1_desc, base);
+ imc->vcoclk = clk;
+ imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
+
+ /* UART reference clock */
+ clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
+ 14745600);
+ imc->uartclk = clk;
+ imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
+ imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
+
+ for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
+ clkdev_add(imc->clks[i]);
+}
+
+void integrator_impd1_clk_exit(unsigned int id)
+{
+ int i;
+ struct impd1_clk *imc;
+
+ if (id > 3)
+ return;
+ imc = &impd1_clks[id];
+
+ for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
+ clkdev_drop(imc->clks[i]);
+ clk_unregister(imc->uartclk);
+ clk_unregister(imc->vcoclk);
+}
diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c
index a5053921bf7f..08593b4ee2c9 100644
--- a/drivers/clk/versatile/clk-integrator.c
+++ b/drivers/clk/versatile/clk-integrator.c
@@ -1,8 +1,16 @@
+/*
+ * Clock driver for the ARM Integrator/AP and Integrator/CP boards
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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-provider.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/clk-provider.h>
+#include <linux/platform_data/clk-integrator.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -14,42 +22,6 @@
* Inspired by portions of:
* plat-versatile/clock.c and plat-versatile/include/plat/clock.h
*/
-#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
-#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c)
-
-/**
- * cp_auxvco_get() - get ICST VCO settings for the Integrator/CP
- * @vco: ICST VCO parameters to update with hardware status
- */
-static struct icst_vco cp_auxvco_get(void)
-{
- u32 val;
- struct icst_vco vco;
-
- val = readl(CM_AUXOSC);
- vco.v = val & 0x1ff;
- vco.r = (val >> 9) & 0x7f;
- vco.s = (val >> 16) & 03;
- return vco;
-}
-
-/**
- * cp_auxvco_set() - commit changes to Integrator/CP ICST VCO
- * @vco: ICST VCO parameters to commit
- */
-static void cp_auxvco_set(struct icst_vco vco)
-{
- u32 val;
-
- val = readl(CM_AUXOSC) & ~0x7ffff;
- val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
- /* This magic unlocks the CM VCO so it can be controlled */
- writel(0xa05f, CM_LOCK);
- writel(val, CM_AUXOSC);
- /* This locks the CM again */
- writel(0, CM_LOCK);
-}
static const struct icst_params cp_auxvco_params = {
.ref = 24000000,
@@ -65,8 +37,8 @@ static const struct icst_params cp_auxvco_params = {
static const struct clk_icst_desc __initdata cp_icst_desc = {
.params = &cp_auxvco_params,
- .getvco = cp_auxvco_get,
- .setvco = cp_auxvco_set,
+ .vco_offset = 0x1c,
+ .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET,
};
/*
@@ -106,6 +78,7 @@ void __init integrator_clk_init(bool is_cp)
clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock used on the Integrator/CP CLCD */
- clk = icst_clk_register(NULL, &cp_icst_desc);
+ clk = icst_clk_register(NULL, &cp_icst_desc,
+ __io_address(INTEGRATOR_HDR_BASE));
clk_register_clkdev(clk, NULL, "clcd");
}
diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c
index e21a99cef378..cda07e70a408 100644
--- a/drivers/clk/versatile/clk-realview.c
+++ b/drivers/clk/versatile/clk-realview.c
@@ -1,3 +1,11 @@
+/*
+ * Clock driver for the ARM RealView boards
+ * Copyright (C) 2012 Linus Walleij
+ *
+ * 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/clkdev.h>
#include <linux/err.h>
@@ -13,38 +21,6 @@
* Implementation of the ARM RealView clock trees.
*/
-static void __iomem *sys_lock;
-static void __iomem *sys_vcoreg;
-
-/**
- * realview_oscvco_get() - get ICST OSC settings for the RealView
- */
-static struct icst_vco realview_oscvco_get(void)
-{
- u32 val;
- struct icst_vco vco;
-
- val = readl(sys_vcoreg);
- vco.v = val & 0x1ff;
- vco.r = (val >> 9) & 0x7f;
- vco.s = (val >> 16) & 03;
- return vco;
-}
-
-static void realview_oscvco_set(struct icst_vco vco)
-{
- u32 val;
-
- val = readl(sys_vcoreg) & ~0x7ffff;
- val |= vco.v | (vco.r << 9) | (vco.s << 16);
-
- /* This magic unlocks the CM VCO so it can be controlled */
- writel(0xa05f, sys_lock);
- writel(val, sys_vcoreg);
- /* This locks the CM again */
- writel(0, sys_lock);
-}
-
static const struct icst_params realview_oscvco_params = {
.ref = 24000000,
.vco_max = ICST307_VCO_MAX,
@@ -57,10 +33,16 @@ static const struct icst_params realview_oscvco_params = {
.idx2s = icst307_idx2s,
};
-static const struct clk_icst_desc __initdata realview_icst_desc = {
+static const struct clk_icst_desc __initdata realview_osc0_desc = {
+ .params = &realview_oscvco_params,
+ .vco_offset = REALVIEW_SYS_OSC0_OFFSET,
+ .lock_offset = REALVIEW_SYS_LOCK_OFFSET,
+};
+
+static const struct clk_icst_desc __initdata realview_osc4_desc = {
.params = &realview_oscvco_params,
- .getvco = realview_oscvco_get,
- .setvco = realview_oscvco_set,
+ .vco_offset = REALVIEW_SYS_OSC4_OFFSET,
+ .lock_offset = REALVIEW_SYS_LOCK_OFFSET,
};
/*
@@ -70,13 +52,6 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
{
struct clk *clk;
- sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET;
- if (is_pb1176)
- sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET;
- else
- sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET;
-
-
/* APB clock dummy */
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
clk_register_clkdev(clk, "apb_pclk", NULL);
@@ -108,7 +83,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176)
clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock */
- clk = icst_clk_register(NULL, &realview_icst_desc);
+ if (is_pb1176)
+ clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase);
+ else
+ clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase);
+
clk_register_clkdev(clk, NULL, "dev:clcd");
clk_register_clkdev(clk, NULL, "issp:clcd");
}
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
new file mode 100644
index 000000000000..dcb6ae0a0425
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -0,0 +1,146 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#define pr_fmt(fmt) "vexpress-osc: " fmt
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/vexpress.h>
+
+struct vexpress_osc {
+ struct vexpress_config_func *func;
+ struct clk_hw hw;
+ unsigned long rate_min;
+ unsigned long rate_max;
+};
+
+#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw)
+
+static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct vexpress_osc *osc = to_vexpress_osc(hw);
+ u32 rate;
+
+ vexpress_config_read(osc->func, 0, &rate);
+
+ return rate;
+}
+
+static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+ if (WARN_ON(osc->rate_min && rate < osc->rate_min))
+ rate = osc->rate_min;
+
+ if (WARN_ON(osc->rate_max && rate > osc->rate_max))
+ rate = osc->rate_max;
+
+ return rate;
+}
+
+static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct vexpress_osc *osc = to_vexpress_osc(hw);
+
+ return vexpress_config_write(osc->func, 0, rate);
+}
+
+static struct clk_ops vexpress_osc_ops = {
+ .recalc_rate = vexpress_osc_recalc_rate,
+ .round_rate = vexpress_osc_round_rate,
+ .set_rate = vexpress_osc_set_rate,
+};
+
+
+struct clk * __init vexpress_osc_setup(struct device *dev)
+{
+ struct clk_init_data init;
+ struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+
+ if (!osc)
+ return NULL;
+
+ osc->func = vexpress_config_func_get_by_dev(dev);
+ if (!osc->func) {
+ kfree(osc);
+ return NULL;
+ }
+
+ init.name = dev_name(dev);
+ init.ops = &vexpress_osc_ops;
+ init.flags = CLK_IS_ROOT;
+ init.num_parents = 0;
+ osc->hw.init = &init;
+
+ return clk_register(NULL, &osc->hw);
+}
+
+void __init vexpress_osc_of_setup(struct device_node *node)
+{
+ struct clk_init_data init;
+ struct vexpress_osc *osc;
+ struct clk *clk;
+ u32 range[2];
+
+ osc = kzalloc(sizeof(*osc), GFP_KERNEL);
+ if (!osc)
+ goto error;
+
+ osc->func = vexpress_config_func_get_by_node(node);
+ if (!osc->func) {
+ pr_err("Failed to obtain config func for node '%s'!\n",
+ node->name);
+ goto error;
+ }
+
+ if (of_property_read_u32_array(node, "freq-range", range,
+ ARRAY_SIZE(range)) == 0) {
+ osc->rate_min = range[0];
+ osc->rate_max = range[1];
+ }
+
+ of_property_read_string(node, "clock-output-names", &init.name);
+ if (!init.name)
+ init.name = node->name;
+
+ init.ops = &vexpress_osc_ops;
+ init.flags = CLK_IS_ROOT;
+ init.num_parents = 0;
+
+ osc->hw.init = &init;
+
+ clk = clk_register(NULL, &osc->hw);
+ if (IS_ERR(clk)) {
+ pr_err("Failed to register clock '%s'!\n", init.name);
+ goto error;
+ }
+
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+ pr_debug("Registered clock '%s'\n", init.name);
+
+ return;
+
+error:
+ if (osc->func)
+ vexpress_config_func_put(osc->func);
+ kfree(osc);
+}
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
new file mode 100644
index 000000000000..c742ac7c60bb
--- /dev/null
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -0,0 +1,142 @@
+/*
+ * 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) 2012 ARM Limited
+ */
+
+#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>
+
+#include <asm/hardware/sp810.h>
+
+static struct clk *vexpress_sp810_timerclken[4];
+static DEFINE_SPINLOCK(vexpress_sp810_lock);
+
+static void __init vexpress_sp810_init(void __iomem *base)
+{
+ int i;
+
+ if (WARN_ON(!base))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) {
+ char name[12];
+ const char *parents[] = {
+ "v2m:refclk32khz", /* REFCLK */
+ "v2m:refclk1mhz" /* TIMCLK */
+ };
+
+ snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
+
+ vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
+ parents, 2, 0, base + SCCTRL,
+ SCCTRL_TIMERENnSEL_SHIFT(i), 1,
+ 0, &vexpress_sp810_lock);
+
+ if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
+ break;
+ }
+}
+
+
+static const char * const vexpress_clk_24mhz_periphs[] __initconst = {
+ "mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3",
+ "mb:mmci", "mb:kmi0", "mb:kmi1"
+};
+
+void __init vexpress_clk_init(void __iomem *sp810_base)
+{
+ struct clk *clk;
+ int i;
+
+ clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
+ CLK_IS_ROOT, 0);
+ WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
+
+ clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL,
+ CLK_IS_ROOT, 24000000);
+ for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++)
+ WARN_ON(clk_register_clkdev(clk, NULL,
+ vexpress_clk_24mhz_periphs[i]));
+
+ clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL,
+ CLK_IS_ROOT, 32768);
+ WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt"));
+
+ clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL,
+ CLK_IS_ROOT, 1000000);
+
+ vexpress_sp810_init(sp810_base);
+
+ 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"));
+}
+
+#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]];
+}
+
+static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
+ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+ { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
+ {}
+};
+
+void __init vexpress_clk_of_init(void)
+{
+ struct device_node *node;
+ struct clk *clk;
+ struct clk *refclk, *timclk;
+
+ of_clk_init(vexpress_fixed_clk_match);
+
+ 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/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index 74b830b635a6..4f154bc0ebe4 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -8,43 +8,17 @@
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
#include <mach/id.h>
-static struct cpufreq_frequency_table freq_table[] = {
- [0] = {
- .index = 0,
- .frequency = 200000,
- },
- [1] = {
- .index = 1,
- .frequency = 400000,
- },
- [2] = {
- .index = 2,
- .frequency = 800000,
- },
- [3] = {
- /* Used for MAX_OPP, if available */
- .index = 3,
- .frequency = CPUFREQ_TABLE_END,
- },
- [4] = {
- .index = 4,
- .frequency = CPUFREQ_TABLE_END,
- },
-};
-
-static enum arm_opp idx2opp[] = {
- ARM_EXTCLK,
- ARM_50_OPP,
- ARM_100_OPP,
- ARM_MAX_OPP
-};
+static struct cpufreq_frequency_table *freq_table;
+static struct clk *armss_clk;
static struct freq_attr *db8500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
@@ -85,9 +59,9 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
for_each_cpu(freqs.cpu, policy->cpus)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- /* request the PRCM unit for opp change */
- if (prcmu_set_arm_opp(idx2opp[idx])) {
- pr_err("db8500-cpufreq: Failed to set OPP level\n");
+ /* update armss clk frequency */
+ if (clk_set_rate(armss_clk, freq_table[idx].frequency * 1000)) {
+ pr_err("db8500-cpufreq: Failed to update armss clk\n");
return -EINVAL;
}
@@ -100,25 +74,36 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy,
static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
{
- int i;
- /* request the prcm to get the current ARM opp */
- for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
- ;
- return freq_table[i].frequency;
+ 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)
+ return freq_table[i].frequency;
+ i++;
+ }
+
+ /* We could not find a corresponding frequency. */
+ pr_err("db8500-cpufreq: Failed to find cpufreq speed\n");
+ return 0;
}
static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
{
- int i, res;
-
- BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
+ int i = 0;
+ int res;
- if (prcmu_has_arm_maxopp())
- freq_table[3].frequency = 1000000;
+ armss_clk = clk_get(NULL, "armss");
+ if (IS_ERR(armss_clk)) {
+ pr_err("db8500-cpufreq : Failed to get armss clk\n");
+ return PTR_ERR(armss_clk);
+ }
pr_info("db8500-cpufreq : Available frequencies:\n");
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
+ while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
+ i++;
+ }
/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
@@ -126,6 +111,7 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else {
pr_err("db8500-cpufreq : Failed to read policy table\n");
+ clk_put(armss_clk);
return res;
}
@@ -159,12 +145,35 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
.attr = db8500_cpufreq_attr,
};
+static int db8500_cpufreq_probe(struct platform_device *pdev)
+{
+ freq_table = dev_get_platdata(&pdev->dev);
+
+ if (!freq_table) {
+ pr_err("db8500-cpufreq: Failed to fetch cpufreq table\n");
+ return -ENODEV;
+ }
+
+ return cpufreq_register_driver(&db8500_cpufreq_driver);
+}
+
+static struct platform_driver db8500_cpufreq_plat_driver = {
+ .driver = {
+ .name = "cpufreq-u8500",
+ .owner = THIS_MODULE,
+ },
+ .probe = db8500_cpufreq_probe,
+};
+
static int __init db8500_cpufreq_register(void)
{
if (!cpu_is_u8500_family())
return -ENODEV;
pr_info("cpufreq for DB8500 started\n");
- return cpufreq_register_driver(&db8500_cpufreq_driver);
+ return platform_driver_register(&db8500_cpufreq_plat_driver);
}
device_initcall(db8500_cpufreq_register);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("cpufreq driver for DB8500");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 308c7fb92a60..f6644f59fd9d 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -224,7 +224,7 @@ config CRYPTO_DEV_TALITOS
config CRYPTO_DEV_IXP4XX
tristate "Driver for IXP4xx crypto hardware acceleration"
- depends on ARCH_IXP4XX
+ depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE
select CRYPTO_DES
select CRYPTO_ALGAPI
select CRYPTO_AUTHENC
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index 8f3f74ce8c7f..21180d6cad6e 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -750,12 +750,12 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt,
}
if (cipher_cfg & MOD_AES) {
switch (key_len) {
- case 16: keylen_cfg = MOD_AES128 | KEYLEN_128; break;
- case 24: keylen_cfg = MOD_AES192 | KEYLEN_192; break;
- case 32: keylen_cfg = MOD_AES256 | KEYLEN_256; break;
- default:
- *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
- return -EINVAL;
+ case 16: keylen_cfg = MOD_AES128; break;
+ case 24: keylen_cfg = MOD_AES192; break;
+ case 32: keylen_cfg = MOD_AES256; break;
+ default:
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
}
cipher_cfg |= keylen_cfg;
} else if (cipher_cfg & MOD_3DES) {
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 409b92b8d346..bb82d6be793c 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -42,10 +42,10 @@ config EDAC_LEGACY_SYSFS
config EDAC_DEBUG
bool "Debugging"
help
- This turns on debugging information for the entire EDAC
- sub-system. You can insert module with "debug_level=x", current
- there're four debug levels (x=0,1,2,3 from low to high).
- Usually you should select 'N'.
+ This turns on debugging information for the entire EDAC subsystem.
+ You do so by inserting edac_module with "edac_debug_level=x." Valid
+ levels are 0-4 (from low to high) and by default it is set to 2.
+ Usually you should select 'N' here.
config EDAC_DECODE_MCE
tristate "Decode MCEs in human-readable form (only on AMD for now)"
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index cc8e7c78a23c..f74a684269ff 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -60,8 +60,8 @@ struct scrubrate {
{ 0x00, 0UL}, /* scrubbing off */
};
-static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
- u32 *val, const char *func)
+int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
+ u32 *val, const char *func)
{
int err = 0;
@@ -423,7 +423,6 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
u64 *hole_offset, u64 *hole_size)
{
struct amd64_pvt *pvt = mci->pvt_info;
- u64 base;
/* only revE and later have the DRAM Hole Address Register */
if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
@@ -462,10 +461,8 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
* addresses in the hole so that they start at 0x100000000.
*/
- base = dhar_base(pvt);
-
- *hole_base = base;
- *hole_size = (0x1ull << 32) - base;
+ *hole_base = dhar_base(pvt);
+ *hole_size = (1ULL << 32) - *hole_base;
if (boot_cpu_data.x86 > 0xf)
*hole_offset = f10_dhar_offset(pvt);
@@ -513,15 +510,15 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr)
{
struct amd64_pvt *pvt = mci->pvt_info;
u64 dram_base, hole_base, hole_offset, hole_size, dram_addr;
- int ret = 0;
+ int ret;
dram_base = get_dram_base(pvt, pvt->mc_node_id);
ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset,
&hole_size);
if (!ret) {
- if ((sys_addr >= (1ull << 32)) &&
- (sys_addr < ((1ull << 32) + hole_size))) {
+ if ((sys_addr >= (1ULL << 32)) &&
+ (sys_addr < ((1ULL << 32) + hole_size))) {
/* use DHAR to translate SysAddr to DramAddr */
dram_addr = sys_addr - hole_offset;
@@ -712,10 +709,10 @@ static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
/* Map the Error address to a PAGE and PAGE OFFSET. */
static inline void error_address_to_page_and_offset(u64 error_address,
- u32 *page, u32 *offset)
+ struct err_info *err)
{
- *page = (u32) (error_address >> PAGE_SHIFT);
- *offset = ((u32) error_address) & ~PAGE_MASK;
+ err->page = (u32) (error_address >> PAGE_SHIFT);
+ err->offset = ((u32) error_address) & ~PAGE_MASK;
}
/*
@@ -1026,59 +1023,44 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
}
static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
- u16 syndrome)
+ struct err_info *err)
{
- struct mem_ctl_info *src_mci;
struct amd64_pvt *pvt = mci->pvt_info;
- int channel, csrow;
- u32 page, offset;
- error_address_to_page_and_offset(sys_addr, &page, &offset);
+ error_address_to_page_and_offset(sys_addr, err);
/*
* Find out which node the error address belongs to. This may be
* different from the node that detected the error.
*/
- src_mci = find_mc_by_sys_addr(mci, sys_addr);
- if (!src_mci) {
+ err->src_mci = find_mc_by_sys_addr(mci, sys_addr);
+ if (!err->src_mci) {
amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
(unsigned long)sys_addr);
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- page, offset, syndrome,
- -1, -1, -1,
- "failed to map error addr to a node",
- "");
+ err->err_code = ERR_NODE;
return;
}
/* Now map the sys_addr to a CSROW */
- csrow = sys_addr_to_csrow(src_mci, sys_addr);
- if (csrow < 0) {
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- page, offset, syndrome,
- -1, -1, -1,
- "failed to map error addr to a csrow",
- "");
+ err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr);
+ if (err->csrow < 0) {
+ err->err_code = ERR_CSROW;
return;
}
/* CHIPKILL enabled */
if (pvt->nbcfg & NBCFG_CHIPKILL) {
- channel = get_channel_from_ecc_syndrome(mci, syndrome);
- if (channel < 0) {
+ err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
+ if (err->channel < 0) {
/*
* Syndrome didn't map, so we don't know which of the
* 2 DIMMs is in error. So we need to ID 'both' of them
* as suspect.
*/
- amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - "
+ amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - "
"possible error reporting race\n",
- syndrome);
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- page, offset, syndrome,
- csrow, -1, -1,
- "unknown syndrome - possible error reporting race",
- "");
+ err->syndrome);
+ err->err_code = ERR_CHANNEL;
return;
}
} else {
@@ -1090,13 +1072,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
* was obtained from email communication with someone at AMD.
* (Wish the email was placed in this comment - norsk)
*/
- channel = ((sys_addr & BIT(3)) != 0);
+ err->channel = ((sys_addr & BIT(3)) != 0);
}
-
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci, 1,
- page, offset, syndrome,
- csrow, channel, -1,
- "", "");
}
static int ddr2_cs_size(unsigned i, bool dct_width)
@@ -1482,7 +1459,7 @@ static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
/* For a given @dram_range, check if @sys_addr falls within it. */
static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
- u64 sys_addr, int *nid, int *chan_sel)
+ u64 sys_addr, int *chan_sel)
{
int cs_found = -EINVAL;
u64 chan_addr;
@@ -1555,15 +1532,14 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
- if (cs_found >= 0) {
- *nid = node_id;
+ if (cs_found >= 0)
*chan_sel = channel;
- }
+
return cs_found;
}
static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
- int *node, int *chan_sel)
+ int *chan_sel)
{
int cs_found = -EINVAL;
unsigned range;
@@ -1577,8 +1553,7 @@ static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
(get_dram_limit(pvt, range) >= sys_addr)) {
cs_found = f1x_match_to_this_node(pvt, range,
- sys_addr, node,
- chan_sel);
+ sys_addr, chan_sel);
if (cs_found >= 0)
break;
}
@@ -1594,22 +1569,15 @@ static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
* (MCX_ADDR).
*/
static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
- u16 syndrome)
+ struct err_info *err)
{
struct amd64_pvt *pvt = mci->pvt_info;
- u32 page, offset;
- int nid, csrow, chan = 0;
- error_address_to_page_and_offset(sys_addr, &page, &offset);
+ error_address_to_page_and_offset(sys_addr, err);
- csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
-
- if (csrow < 0) {
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- page, offset, syndrome,
- -1, -1, -1,
- "failed to map error addr to a csrow",
- "");
+ err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel);
+ if (err->csrow < 0) {
+ err->err_code = ERR_CSROW;
return;
}
@@ -1619,12 +1587,7 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
* this point.
*/
if (dct_ganging_enabled(pvt))
- chan = get_channel_from_ecc_syndrome(mci, syndrome);
-
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- page, offset, syndrome,
- csrow, chan, -1,
- "", "");
+ err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome);
}
/*
@@ -1633,14 +1596,11 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
*/
static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
{
- int dimm, size0, size1, factor = 0;
+ int dimm, size0, size1;
u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases;
u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
if (boot_cpu_data.x86 == 0xf) {
- if (pvt->dclr0 & WIDTH_128)
- factor = 1;
-
/* K8 families < revF not supported yet */
if (pvt->ext_model < K8_REV_F)
return;
@@ -1671,8 +1631,8 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
DBAM_DIMM(dimm, dbam));
amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
- dimm * 2, size0 << factor,
- dimm * 2 + 1, size1 << factor);
+ dimm * 2, size0,
+ dimm * 2 + 1, size1);
}
}
@@ -1893,101 +1853,56 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz);
}
-/*
- * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
- * ADDRESS and process.
- */
-static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
-{
- struct amd64_pvt *pvt = mci->pvt_info;
- u64 sys_addr;
- u16 syndrome;
-
- /* Ensure that the Error Address is VALID */
- if (!(m->status & MCI_STATUS_ADDRV)) {
- amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
- edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
- 0, 0, 0,
- -1, -1, -1,
- "HW has no ERROR_ADDRESS available",
- "");
- return;
- }
-
- sys_addr = get_error_address(m);
- syndrome = extract_syndrome(m->status);
-
- amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
-
- pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome);
-}
-
-/* Handle any Un-correctable Errors (UEs) */
-static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
+static void __log_bus_error(struct mem_ctl_info *mci, struct err_info *err,
+ u8 ecc_type)
{
- struct mem_ctl_info *log_mci, *src_mci = NULL;
- int csrow;
- u64 sys_addr;
- u32 page, offset;
-
- log_mci = mci;
+ enum hw_event_mc_err_type err_type;
+ const char *string;
- if (!(m->status & MCI_STATUS_ADDRV)) {
- amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
- 0, 0, 0,
- -1, -1, -1,
- "HW has no ERROR_ADDRESS available",
- "");
+ if (ecc_type == 2)
+ err_type = HW_EVENT_ERR_CORRECTED;
+ else if (ecc_type == 1)
+ err_type = HW_EVENT_ERR_UNCORRECTED;
+ else {
+ WARN(1, "Something is rotten in the state of Denmark.\n");
return;
}
- sys_addr = get_error_address(m);
- error_address_to_page_and_offset(sys_addr, &page, &offset);
-
- /*
- * Find out which node the error address belongs to. This may be
- * different from the node that detected the error.
- */
- src_mci = find_mc_by_sys_addr(mci, sys_addr);
- if (!src_mci) {
- amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
- (unsigned long)sys_addr);
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
- page, offset, 0,
- -1, -1, -1,
- "ERROR ADDRESS NOT mapped to a MC",
- "");
- return;
+ switch (err->err_code) {
+ case DECODE_OK:
+ string = "";
+ break;
+ case ERR_NODE:
+ string = "Failed to map error addr to a node";
+ break;
+ case ERR_CSROW:
+ string = "Failed to map error addr to a csrow";
+ break;
+ case ERR_CHANNEL:
+ string = "unknown syndrome - possible error reporting race";
+ break;
+ default:
+ string = "WTF error";
+ break;
}
- log_mci = src_mci;
-
- csrow = sys_addr_to_csrow(log_mci, sys_addr);
- if (csrow < 0) {
- amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
- (unsigned long)sys_addr);
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
- page, offset, 0,
- -1, -1, -1,
- "ERROR ADDRESS NOT mapped to CS",
- "");
- } else {
- edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
- page, offset, 0,
- csrow, -1, -1,
- "", "");
- }
+ edac_mc_handle_error(err_type, mci, 1,
+ err->page, err->offset, err->syndrome,
+ err->csrow, err->channel, -1,
+ string, "");
}
static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
struct mce *m)
{
- u16 ec = EC(m->status);
- u8 xec = XEC(m->status, 0x1f);
+ struct amd64_pvt *pvt = mci->pvt_info;
u8 ecc_type = (m->status >> 45) & 0x3;
+ u8 xec = XEC(m->status, 0x1f);
+ u16 ec = EC(m->status);
+ u64 sys_addr;
+ struct err_info err;
- /* Bail early out if this was an 'observed' error */
+ /* Bail out early if this was an 'observed' error */
if (PP(ec) == NBSL_PP_OBS)
return;
@@ -1995,10 +1910,16 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
if (xec && xec != F10_NBSL_EXT_ERR_ECC)
return;
+ memset(&err, 0, sizeof(err));
+
+ sys_addr = get_error_address(m);
+
if (ecc_type == 2)
- amd64_handle_ce(mci, m);
- else if (ecc_type == 1)
- amd64_handle_ue(mci, m);
+ err.syndrome = extract_syndrome(m->status);
+
+ pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err);
+
+ __log_bus_error(mci, &err, ecc_type);
}
void amd64_decode_bus_error(int node_id, struct mce *m)
@@ -2166,6 +2087,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
u32 cs_mode, nr_pages;
u32 dbam = dct ? pvt->dbam1 : pvt->dbam0;
+
/*
* The math on this doesn't look right on the surface because x/2*4 can
* be simplified to x*2 but this expression makes use of the fact that
@@ -2173,13 +2095,13 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
* number of bits to shift the DBAM register to extract the proper CSROW
* field.
*/
- cs_mode = (dbam >> ((csrow_nr / 2) * 4)) & 0xF;
+ cs_mode = DBAM_DIMM(csrow_nr / 2, dbam);
nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
- edac_dbg(0, " (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
- edac_dbg(0, " nr_pages/channel= %u channel-count = %d\n",
- nr_pages, pvt->channel_count);
+ edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n",
+ csrow_nr, dct, cs_mode);
+ edac_dbg(0, "nr_pages/channel: %u\n", nr_pages);
return nr_pages;
}
@@ -2190,15 +2112,14 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
*/
static int init_csrows(struct mem_ctl_info *mci)
{
+ struct amd64_pvt *pvt = mci->pvt_info;
struct csrow_info *csrow;
struct dimm_info *dimm;
- struct amd64_pvt *pvt = mci->pvt_info;
- u64 base, mask;
- u32 val;
- int i, j, empty = 1;
- enum mem_type mtype;
enum edac_type edac_mode;
+ enum mem_type mtype;
+ int i, j, empty = 1;
int nr_pages = 0;
+ u32 val;
amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
@@ -2208,29 +2129,35 @@ static int init_csrows(struct mem_ctl_info *mci)
pvt->mc_node_id, val,
!!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE));
+ /*
+ * We iterate over DCT0 here but we look at DCT1 in parallel, if needed.
+ */
for_each_chip_select(i, 0, pvt) {
- csrow = mci->csrows[i];
+ bool row_dct0 = !!csrow_enabled(i, 0, pvt);
+ bool row_dct1 = false;
+
+ if (boot_cpu_data.x86 != 0xf)
+ row_dct1 = !!csrow_enabled(i, 1, pvt);
- if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) {
- edac_dbg(1, "----CSROW %d VALID for MC node %d\n",
- i, pvt->mc_node_id);
+ if (!row_dct0 && !row_dct1)
continue;
- }
+ csrow = mci->csrows[i];
empty = 0;
- if (csrow_enabled(i, 0, pvt))
+
+ edac_dbg(1, "MC node: %d, csrow: %d\n",
+ pvt->mc_node_id, i);
+
+ if (row_dct0)
nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
- if (csrow_enabled(i, 1, pvt))
- nr_pages += amd64_csrow_nr_pages(pvt, 1, i);
- get_cs_base_and_mask(pvt, i, 0, &base, &mask);
- /* 8 bytes of resolution */
+ /* K8 has only one DCT */
+ if (boot_cpu_data.x86 != 0xf && row_dct1)
+ nr_pages += amd64_csrow_nr_pages(pvt, 1, i);
mtype = amd64_determine_memory_type(pvt, i);
- edac_dbg(1, " for MC node %d csrow %d:\n", pvt->mc_node_id, i);
- edac_dbg(1, " nr_pages: %u\n",
- nr_pages * pvt->channel_count);
+ edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
/*
* determine whether CHIPKILL or JUST ECC or NO ECC is operating
@@ -2247,6 +2174,7 @@ static int init_csrows(struct mem_ctl_info *mci)
dimm->edac_mode = edac_mode;
dimm->nr_pages = nr_pages;
}
+ csrow->nr_pages = nr_pages;
}
return empty;
@@ -2591,6 +2519,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
mci->pvt_info = pvt;
mci->pdev = &pvt->F2->dev;
+ mci->csbased = 1;
setup_mci_misc_attrs(mci, fam_type);
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 8d4804732bac..e864f407806c 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -33,7 +33,7 @@
* detection. The mods to Rev F required more family
* information detection.
*
- * Changes/Fixes by Borislav Petkov <borislav.petkov@amd.com>:
+ * Changes/Fixes by Borislav Petkov <bp@alien8.de>:
* - misc fixes and code cleanups
*
* This module is based on the following documents
@@ -219,7 +219,7 @@
#define DBAM1 0x180
/* Extract the DIMM 'type' on the i'th DIMM from the DBAM reg value passed */
-#define DBAM_DIMM(i, reg) ((((reg) >> (4*i))) & 0xF)
+#define DBAM_DIMM(i, reg) ((((reg) >> (4*(i)))) & 0xF)
#define DBAM_MAX_VALUE 11
@@ -267,18 +267,20 @@
#define online_spare_bad_dramcs(pvt, c) (((pvt)->online_spare >> (4 + 4 * (c))) & 0x7)
#define F10_NB_ARRAY_ADDR 0xB8
-#define F10_NB_ARRAY_DRAM_ECC BIT(31)
+#define F10_NB_ARRAY_DRAM BIT(31)
/* Bits [2:1] are used to select 16-byte section within a 64-byte cacheline */
-#define SET_NB_ARRAY_ADDRESS(section) (((section) & 0x3) << 1)
+#define SET_NB_ARRAY_ADDR(section) (((section) & 0x3) << 1)
#define F10_NB_ARRAY_DATA 0xBC
-#define SET_NB_DRAM_INJECTION_WRITE(word, bits) \
- (BIT(((word) & 0xF) + 20) | \
- BIT(17) | bits)
-#define SET_NB_DRAM_INJECTION_READ(word, bits) \
- (BIT(((word) & 0xF) + 20) | \
- BIT(16) | bits)
+#define F10_NB_ARR_ECC_WR_REQ BIT(17)
+#define SET_NB_DRAM_INJECTION_WRITE(inj) \
+ (BIT(((inj.word) & 0xF) + 20) | \
+ F10_NB_ARR_ECC_WR_REQ | inj.bit_map)
+#define SET_NB_DRAM_INJECTION_READ(inj) \
+ (BIT(((inj.word) & 0xF) + 20) | \
+ BIT(16) | inj.bit_map)
+
#define NBCAP 0xE8
#define NBCAP_CHIPKILL BIT(4)
@@ -305,9 +307,9 @@ enum amd_families {
/* Error injection control structure */
struct error_injection {
- u32 section;
- u32 word;
- u32 bit_map;
+ u32 section;
+ u32 word;
+ u32 bit_map;
};
/* low and high part of PCI config space regs */
@@ -374,6 +376,23 @@ struct amd64_pvt {
struct error_injection injection;
};
+enum err_codes {
+ DECODE_OK = 0,
+ ERR_NODE = -1,
+ ERR_CSROW = -2,
+ ERR_CHANNEL = -3,
+};
+
+struct err_info {
+ int err_code;
+ struct mem_ctl_info *src_mci;
+ int csrow;
+ int channel;
+ u16 syndrome;
+ u32 page;
+ u32 offset;
+};
+
static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
{
u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;
@@ -447,7 +466,7 @@ static inline void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
struct low_ops {
int (*early_channel_count) (struct amd64_pvt *pvt);
void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr,
- u16 syndrome);
+ struct err_info *);
int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode);
int (*read_dct_pci_cfg) (struct amd64_pvt *pvt, int offset,
u32 *val, const char *func);
@@ -459,6 +478,8 @@ struct amd64_family_type {
struct low_ops ops;
};
+int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset,
+ u32 *val, const char *func);
int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset,
u32 val, const char *func);
@@ -475,3 +496,15 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
u64 *hole_offset, u64 *hole_size);
#define to_mci(k) container_of(k, struct mem_ctl_info, dev)
+
+/* Injection helpers */
+static inline void disable_caches(void *dummy)
+{
+ write_cr0(read_cr0() | X86_CR0_CD);
+ wbinvd();
+}
+
+static inline void enable_caches(void *dummy)
+{
+ write_cr0(read_cr0() & ~X86_CR0_CD);
+}
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index 53d972e00dfb..8c171fa1cb9b 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -22,20 +22,19 @@ static ssize_t amd64_inject_section_store(struct device *dev,
struct mem_ctl_info *mci = to_mci(dev);
struct amd64_pvt *pvt = mci->pvt_info;
unsigned long value;
- int ret = 0;
+ int ret;
ret = strict_strtoul(data, 10, &value);
- if (ret != -EINVAL) {
+ if (ret < 0)
+ return ret;
- if (value > 3) {
- amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
- return -EINVAL;
- }
-
- pvt->injection.section = (u32) value;
- return count;
+ if (value > 3) {
+ amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
+ return -EINVAL;
}
- return ret;
+
+ pvt->injection.section = (u32) value;
+ return count;
}
static ssize_t amd64_inject_word_show(struct device *dev,
@@ -60,20 +59,19 @@ static ssize_t amd64_inject_word_store(struct device *dev,
struct mem_ctl_info *mci = to_mci(dev);
struct amd64_pvt *pvt = mci->pvt_info;
unsigned long value;
- int ret = 0;
+ int ret;
ret = strict_strtoul(data, 10, &value);
- if (ret != -EINVAL) {
+ if (ret < 0)
+ return ret;
- if (value > 8) {
- amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
- return -EINVAL;
- }
-
- pvt->injection.word = (u32) value;
- return count;
+ if (value > 8) {
+ amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
+ return -EINVAL;
}
- return ret;
+
+ pvt->injection.word = (u32) value;
+ return count;
}
static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
@@ -97,21 +95,19 @@ static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
struct mem_ctl_info *mci = to_mci(dev);
struct amd64_pvt *pvt = mci->pvt_info;
unsigned long value;
- int ret = 0;
+ int ret;
ret = strict_strtoul(data, 16, &value);
- if (ret != -EINVAL) {
+ if (ret < 0)
+ return ret;
- if (value & 0xFFFF0000) {
- amd64_warn("%s: invalid EccVector: 0x%lx\n",
- __func__, value);
- return -EINVAL;
- }
-
- pvt->injection.bit_map = (u32) value;
- return count;
+ if (value & 0xFFFF0000) {
+ amd64_warn("%s: invalid EccVector: 0x%lx\n", __func__, value);
+ return -EINVAL;
}
- return ret;
+
+ pvt->injection.bit_map = (u32) value;
+ return count;
}
/*
@@ -126,28 +122,25 @@ static ssize_t amd64_inject_read_store(struct device *dev,
struct amd64_pvt *pvt = mci->pvt_info;
unsigned long value;
u32 section, word_bits;
- int ret = 0;
+ int ret;
ret = strict_strtoul(data, 10, &value);
- if (ret != -EINVAL) {
+ if (ret < 0)
+ return ret;
- /* Form value to choose 16-byte section of cacheline */
- section = F10_NB_ARRAY_DRAM_ECC |
- SET_NB_ARRAY_ADDRESS(pvt->injection.section);
- amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
+ /* Form value to choose 16-byte section of cacheline */
+ section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section);
- word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
- pvt->injection.bit_map);
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
- /* Issue 'word' and 'bit' along with the READ request */
- amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
+ word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection);
- edac_dbg(0, "section=0x%x word_bits=0x%x\n",
- section, word_bits);
+ /* Issue 'word' and 'bit' along with the READ request */
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
- return count;
- }
- return ret;
+ edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits);
+
+ return count;
}
/*
@@ -160,30 +153,43 @@ static ssize_t amd64_inject_write_store(struct device *dev,
{
struct mem_ctl_info *mci = to_mci(dev);
struct amd64_pvt *pvt = mci->pvt_info;
+ u32 section, word_bits, tmp;
unsigned long value;
- u32 section, word_bits;
- int ret = 0;
+ int ret;
ret = strict_strtoul(data, 10, &value);
- if (ret != -EINVAL) {
+ if (ret < 0)
+ return ret;
+
+ /* Form value to choose 16-byte section of cacheline */
+ section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section);
+
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
- /* Form value to choose 16-byte section of cacheline */
- section = F10_NB_ARRAY_DRAM_ECC |
- SET_NB_ARRAY_ADDRESS(pvt->injection.section);
- amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
+ word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection);
- word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
- pvt->injection.bit_map);
+ pr_notice_once("Don't forget to decrease MCE polling interval in\n"
+ "/sys/bus/machinecheck/devices/machinecheck<CPUNUM>/check_interval\n"
+ "so that you can get the error report faster.\n");
- /* Issue 'word' and 'bit' along with the READ request */
- amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
+ on_each_cpu(disable_caches, NULL, 1);
- edac_dbg(0, "section=0x%x word_bits=0x%x\n",
- section, word_bits);
+ /* Issue 'word' and 'bit' along with the READ request */
+ amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
- return count;
+ retry:
+ /* wait until injection happens */
+ amd64_read_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, &tmp);
+ if (tmp & F10_NB_ARR_ECC_WR_REQ) {
+ cpu_relax();
+ goto retry;
}
- return ret;
+
+ on_each_cpu(enable_caches, NULL, 1);
+
+ edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits);
+
+ return count;
}
/*
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 90f0b730e9bb..281f566a5513 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -416,10 +416,18 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
dimm->cschannel = chn;
/* Increment csrow location */
- row++;
- if (row == tot_csrows) {
- row = 0;
+ if (layers[0].is_virt_csrow) {
chn++;
+ if (chn == tot_channels) {
+ chn = 0;
+ row++;
+ }
+ } else {
+ row++;
+ if (row == tot_csrows) {
+ row = 0;
+ chn++;
+ }
}
/* Increment dimm location */
@@ -966,20 +974,22 @@ static void edac_ce_error(struct mem_ctl_info *mci,
long grain)
{
unsigned long remapped_page;
+ char *msg_aux = "";
+
+ if (*msg)
+ msg_aux = " ";
if (edac_mc_get_log_ce()) {
if (other_detail && *other_detail)
edac_mc_printk(mci, KERN_WARNING,
- "%d CE %s on %s (%s %s - %s)\n",
- error_count,
- msg, label, location,
- detail, other_detail);
+ "%d CE %s%son %s (%s %s - %s)\n",
+ error_count, msg, msg_aux, label,
+ location, detail, other_detail);
else
edac_mc_printk(mci, KERN_WARNING,
- "%d CE %s on %s (%s %s)\n",
- error_count,
- msg, label, location,
- detail);
+ "%d CE %s%son %s (%s %s)\n",
+ error_count, msg, msg_aux, label,
+ location, detail);
}
edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count);
@@ -1014,27 +1024,31 @@ static void edac_ue_error(struct mem_ctl_info *mci,
const char *other_detail,
const bool enable_per_layer_report)
{
+ char *msg_aux = "";
+
+ if (*msg)
+ msg_aux = " ";
+
if (edac_mc_get_log_ue()) {
if (other_detail && *other_detail)
edac_mc_printk(mci, KERN_WARNING,
- "%d UE %s on %s (%s %s - %s)\n",
- error_count,
- msg, label, location, detail,
- other_detail);
+ "%d UE %s%son %s (%s %s - %s)\n",
+ error_count, msg, msg_aux, label,
+ location, detail, other_detail);
else
edac_mc_printk(mci, KERN_WARNING,
- "%d UE %s on %s (%s %s)\n",
- error_count,
- msg, label, location, detail);
+ "%d UE %s%son %s (%s %s)\n",
+ error_count, msg, msg_aux, label,
+ location, detail);
}
if (edac_mc_get_panic_on_ue()) {
if (other_detail && *other_detail)
- panic("UE %s on %s (%s%s - %s)\n",
- msg, label, location, detail, other_detail);
+ panic("UE %s%son %s (%s%s - %s)\n",
+ msg, msg_aux, label, location, detail, other_detail);
else
- panic("UE %s on %s (%s%s)\n",
- msg, label, location, detail);
+ panic("UE %s%son %s (%s%s)\n",
+ msg, msg_aux, label, location, detail);
}
edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count);
@@ -1093,10 +1107,6 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
*/
for (i = 0; i < mci->n_layers; i++) {
if (pos[i] >= (int)mci->layers[i].size) {
- if (type == HW_EVENT_ERR_CORRECTED)
- p = "CE";
- else
- p = "UE";
edac_mc_printk(mci, KERN_ERR,
"INTERNAL ERROR: %s value is out of range (%d >= %d)\n",
@@ -1128,6 +1138,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
grain = 0;
p = label;
*p = '\0';
+
for (i = 0; i < mci->tot_dimms; i++) {
struct dimm_info *dimm = mci->dimms[i];
@@ -1195,6 +1206,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
/* Fill the RAM location data */
p = location;
+
for (i = 0; i < mci->n_layers; i++) {
if (pos[i] < 0)
continue;
@@ -1207,7 +1219,6 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type,
*(p - 1) = '\0';
/* Report the error via the trace interface */
-
grain_bits = fls_long(grain) + 1;
trace_mc_event(type, msg, label, error_count,
mci->mc_idx, top_layer, mid_layer, low_layer,
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index ed0bc07b8503..de2df92f9c77 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -180,6 +180,9 @@ static ssize_t csrow_size_show(struct device *dev,
int i;
u32 nr_pages = 0;
+ if (csrow->mci->csbased)
+ return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
+
for (i = 0; i < csrow->nr_channels; i++)
nr_pages += csrow->channels[i]->dimm->nr_pages;
return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
@@ -373,6 +376,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
csrow->dev.bus = &mci->bus;
device_initialize(&csrow->dev);
csrow->dev.parent = &mci->dev;
+ csrow->mci = mci;
dev_set_name(&csrow->dev, "csrow%d", index);
dev_set_drvdata(&csrow->dev, csrow);
@@ -777,10 +781,14 @@ static ssize_t mci_size_mb_show(struct device *dev,
for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
struct csrow_info *csrow = mci->csrows[csrow_idx];
- for (j = 0; j < csrow->nr_channels; j++) {
- struct dimm_info *dimm = csrow->channels[j]->dimm;
+ if (csrow->mci->csbased) {
+ total_pages += csrow->nr_pages;
+ } else {
+ for (j = 0; j < csrow->nr_channels; j++) {
+ struct dimm_info *dimm = csrow->channels[j]->dimm;
- total_pages += dimm->nr_pages;
+ total_pages += dimm->nr_pages;
+ }
}
}
@@ -838,14 +846,8 @@ static ssize_t edac_fake_inject_write(struct file *file,
return count;
}
-static int debugfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
static const struct file_operations debug_fake_inject_fops = {
- .open = debugfs_open,
+ .open = simple_open,
.write = edac_fake_inject_write,
.llseek = generic_file_llseek,
};
@@ -1124,10 +1126,15 @@ int __init edac_mc_sysfs_init(void)
edac_subsys = edac_get_sysfs_subsys();
if (edac_subsys == NULL) {
edac_dbg(1, "no edac_subsys\n");
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
+ if (!mci_pdev) {
+ err = -ENOMEM;
+ goto out_put_sysfs;
+ }
mci_pdev->bus = edac_subsys;
mci_pdev->type = &mc_attr_type;
@@ -1136,11 +1143,18 @@ int __init edac_mc_sysfs_init(void)
err = device_add(mci_pdev);
if (err < 0)
- return err;
+ goto out_dev_free;
edac_dbg(0, "device %s created\n", dev_name(mci_pdev));
return 0;
+
+ out_dev_free:
+ kfree(mci_pdev);
+ out_put_sysfs:
+ edac_put_sysfs_subsys();
+ out:
+ return err;
}
void __exit edac_mc_sysfs_exit(void)
@@ -1148,4 +1162,5 @@ void __exit edac_mc_sysfs_exit(void)
put_device(mci_pdev);
device_del(mci_pdev);
edac_put_sysfs_subsys();
+ kfree(mci_pdev);
}
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index 58a28d838f37..12c951a2c33d 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -18,9 +18,29 @@
#define EDAC_VERSION "Ver: 3.0.0"
#ifdef CONFIG_EDAC_DEBUG
+
+static int edac_set_debug_level(const char *buf, struct kernel_param *kp)
+{
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
+
+ if (val < 0 || val > 4)
+ return -EINVAL;
+
+ return param_set_int(buf, kp);
+}
+
/* Values of 0 to 4 will generate output */
int edac_debug_level = 2;
EXPORT_SYMBOL_GPL(edac_debug_level);
+
+module_param_call(edac_debug_level, edac_set_debug_level, param_get_int,
+ &edac_debug_level, 0644);
+MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
#endif
/* scope is to module level only */
@@ -132,10 +152,3 @@ module_exit(edac_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
MODULE_DESCRIPTION("Core library routines for EDAC reporting");
-
-/* refer to *_sysfs.c files for parameters that are exported via sysfs */
-
-#ifdef CONFIG_EDAC_DEBUG
-module_param(edac_debug_level, int, 0644);
-MODULE_PARM_DESC(edac_debug_level, "Debug level");
-#endif
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index ee87ef972ead..dd370f92ace3 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -470,7 +470,8 @@ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
pci->mod_name = mod_name;
pci->ctl_name = EDAC_PCI_GENCTL_NAME;
- pci->edac_check = edac_pci_generic_check;
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ pci->edac_check = edac_pci_generic_check;
pdata->edac_idx = edac_pci_idx++;
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index e164c555a337..dc6e905ee1a5 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -645,20 +645,16 @@ typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
/*
* pci_dev parity list iterator
- * Scan the PCI device list for one pass, looking for SERRORs
- * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
+ *
+ * Scan the PCI device list looking for SERRORs, Master Parity ERRORS or
+ * Parity ERRORs on primary or secondary devices.
*/
static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
{
struct pci_dev *dev = NULL;
- /* request for kernel access to the next PCI device, if any,
- * and while we are looking at it have its reference count
- * bumped until we are done with it
- */
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev)
fn(dev);
- }
}
/*
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index 6c86f6e54558..351945fa2ecd 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -5,7 +5,7 @@
*
* 2007 (c) MontaVista Software, Inc.
* 2010 (c) Advanced Micro Devices Inc.
- * Borislav Petkov <borislav.petkov@amd.com>
+ * Borislav Petkov <bp@alien8.de>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c
index c769f477fd22..7ea4cc2e8bd2 100644
--- a/drivers/edac/highbank_mc_edac.c
+++ b/drivers/edac/highbank_mc_edac.c
@@ -113,14 +113,8 @@ static ssize_t highbank_mc_err_inject_write(struct file *file,
return count;
}
-static int debugfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
static const struct file_operations highbank_mc_debug_inject_fops = {
- .open = debugfs_open,
+ .open = simple_open,
.write = highbank_mc_err_inject_write,
.llseek = generic_file_llseek,
};
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index a09d0667f72a..9d669cd43618 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -197,8 +197,8 @@ static const char *ferr_fat_fbd_name[] = {
[0] = "Memory Write error on non-redundant retry or "
"FBD configuration Write error on retry",
};
-#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28))
-#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3))
+#define GET_FBD_FAT_IDX(fbderr) (((fbderr) >> 28) & 3)
+#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22))
#define FERR_NF_FBD 0xa0
static const char *ferr_nf_fbd_name[] = {
@@ -225,7 +225,7 @@ static const char *ferr_nf_fbd_name[] = {
[1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC",
[0] = "Uncorrectable Data ECC on Replay",
};
-#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28))
+#define GET_FBD_NF_IDX(fbderr) (((fbderr) >> 28) & 3)
#define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\
(1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\
(1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\
@@ -464,7 +464,7 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
errnum = find_first_bit(&errors,
ARRAY_SIZE(ferr_nf_fbd_name));
specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum);
- branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0;
+ branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0;
pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map,
REDMEMA, &syndrome);
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 3672101023bd..10c8c00d6469 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -816,7 +816,7 @@ static ssize_t i7core_inject_store_##param( \
struct device_attribute *mattr, \
const char *data, size_t count) \
{ \
- struct mem_ctl_info *mci = to_mci(dev); \
+ struct mem_ctl_info *mci = dev_get_drvdata(dev); \
struct i7core_pvt *pvt; \
long value; \
int rc; \
@@ -845,7 +845,7 @@ static ssize_t i7core_inject_show_##param( \
struct device_attribute *mattr, \
char *data) \
{ \
- struct mem_ctl_info *mci = to_mci(dev); \
+ struct mem_ctl_info *mci = dev_get_drvdata(dev); \
struct i7core_pvt *pvt; \
\
pvt = mci->pvt_info; \
@@ -1052,7 +1052,7 @@ static ssize_t i7core_show_counter_##param( \
struct device_attribute *mattr, \
char *data) \
{ \
- struct mem_ctl_info *mci = to_mci(dev); \
+ struct mem_ctl_info *mci = dev_get_drvdata(dev); \
struct i7core_pvt *pvt = mci->pvt_info; \
\
edac_dbg(1, "\n"); \
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 069e26c11c4f..a98020409fa9 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -370,10 +370,6 @@ static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
static void i82975x_init_csrows(struct mem_ctl_info *mci,
struct pci_dev *pdev, void __iomem *mch_window)
{
- static const char *labels[4] = {
- "DIMM A1", "DIMM A2",
- "DIMM B1", "DIMM B2"
- };
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
@@ -423,9 +419,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
dimm = mci->csrows[index]->channels[chan]->dimm;
dimm->nr_pages = nr_pages / csrow->nr_channels;
- strncpy(csrow->channels[chan]->dimm->label,
- labels[(index >> 1) + (chan * 2)],
- EDAC_MC_LABEL_LEN);
+
+ snprintf(csrow->channels[chan]->dimm->label, EDAC_MC_LABEL_LEN, "DIMM %c%d",
+ (chan == 0) ? 'A' : 'B',
+ index);
dimm->grain = 1 << 7; /* 128Byte cache-line resolution */
dimm->dtype = i82975x_dram_type(mch_window, index);
dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index d0c372e30de4..ad637572d8c7 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -64,7 +64,7 @@ EXPORT_SYMBOL_GPL(to_msgs);
const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
EXPORT_SYMBOL_GPL(ii_msgs);
-static const char * const f15h_ic_mce_desc[] = {
+static const char * const f15h_mc1_mce_desc[] = {
"UC during a demand linefill from L2",
"Parity error during data load from IC",
"Parity error for IC valid bit",
@@ -84,7 +84,7 @@ static const char * const f15h_ic_mce_desc[] = {
"fetch address FIFO"
};
-static const char * const f15h_cu_mce_desc[] = {
+static const char * const f15h_mc2_mce_desc[] = {
"Fill ECC error on data fills", /* xec = 0x4 */
"Fill parity error on insn fills",
"Prefetcher request FIFO parity error",
@@ -101,7 +101,7 @@ static const char * const f15h_cu_mce_desc[] = {
"PRB address parity error"
};
-static const char * const nb_mce_desc[] = {
+static const char * const mc4_mce_desc[] = {
"DRAM ECC error detected on the NB",
"CRC error detected on HT link",
"Link-defined sync error packets detected on HT link",
@@ -123,7 +123,7 @@ static const char * const nb_mce_desc[] = {
"ECC Error in the Probe Filter directory"
};
-static const char * const fr_ex_mce_desc[] = {
+static const char * const mc5_mce_desc[] = {
"CPU Watchdog timer expire",
"Wakeup array dest tag",
"AG payload array",
@@ -139,7 +139,7 @@ static const char * const fr_ex_mce_desc[] = {
"DE error occurred"
};
-static bool f12h_dc_mce(u16 ec, u8 xec)
+static bool f12h_mc0_mce(u16 ec, u8 xec)
{
bool ret = false;
@@ -157,26 +157,26 @@ static bool f12h_dc_mce(u16 ec, u8 xec)
return ret;
}
-static bool f10h_dc_mce(u16 ec, u8 xec)
+static bool f10h_mc0_mce(u16 ec, u8 xec)
{
if (R4(ec) == R4_GEN && LL(ec) == LL_L1) {
pr_cont("during data scrub.\n");
return true;
}
- return f12h_dc_mce(ec, xec);
+ return f12h_mc0_mce(ec, xec);
}
-static bool k8_dc_mce(u16 ec, u8 xec)
+static bool k8_mc0_mce(u16 ec, u8 xec)
{
if (BUS_ERROR(ec)) {
pr_cont("during system linefill.\n");
return true;
}
- return f10h_dc_mce(ec, xec);
+ return f10h_mc0_mce(ec, xec);
}
-static bool f14h_dc_mce(u16 ec, u8 xec)
+static bool f14h_mc0_mce(u16 ec, u8 xec)
{
u8 r4 = R4(ec);
bool ret = true;
@@ -228,7 +228,7 @@ static bool f14h_dc_mce(u16 ec, u8 xec)
return ret;
}
-static bool f15h_dc_mce(u16 ec, u8 xec)
+static bool f15h_mc0_mce(u16 ec, u8 xec)
{
bool ret = true;
@@ -275,12 +275,12 @@ static bool f15h_dc_mce(u16 ec, u8 xec)
return ret;
}
-static void amd_decode_dc_mce(struct mce *m)
+static void decode_mc0_mce(struct mce *m)
{
u16 ec = EC(m->status);
u8 xec = XEC(m->status, xec_mask);
- pr_emerg(HW_ERR "Data Cache Error: ");
+ pr_emerg(HW_ERR "MC0 Error: ");
/* TLB error signatures are the same across families */
if (TLB_ERROR(ec)) {
@@ -290,13 +290,13 @@ static void amd_decode_dc_mce(struct mce *m)
: (xec ? "multimatch" : "parity")));
return;
}
- } else if (fam_ops->dc_mce(ec, xec))
+ } else if (fam_ops->mc0_mce(ec, xec))
;
else
- pr_emerg(HW_ERR "Corrupted DC MCE info?\n");
+ pr_emerg(HW_ERR "Corrupted MC0 MCE info?\n");
}
-static bool k8_ic_mce(u16 ec, u8 xec)
+static bool k8_mc1_mce(u16 ec, u8 xec)
{
u8 ll = LL(ec);
bool ret = true;
@@ -330,7 +330,7 @@ static bool k8_ic_mce(u16 ec, u8 xec)
return ret;
}
-static bool f14h_ic_mce(u16 ec, u8 xec)
+static bool f14h_mc1_mce(u16 ec, u8 xec)
{
u8 r4 = R4(ec);
bool ret = true;
@@ -349,7 +349,7 @@ static bool f14h_ic_mce(u16 ec, u8 xec)
return ret;
}
-static bool f15h_ic_mce(u16 ec, u8 xec)
+static bool f15h_mc1_mce(u16 ec, u8 xec)
{
bool ret = true;
@@ -358,19 +358,19 @@ static bool f15h_ic_mce(u16 ec, u8 xec)
switch (xec) {
case 0x0 ... 0xa:
- pr_cont("%s.\n", f15h_ic_mce_desc[xec]);
+ pr_cont("%s.\n", f15h_mc1_mce_desc[xec]);
break;
case 0xd:
- pr_cont("%s.\n", f15h_ic_mce_desc[xec-2]);
+ pr_cont("%s.\n", f15h_mc1_mce_desc[xec-2]);
break;
case 0x10:
- pr_cont("%s.\n", f15h_ic_mce_desc[xec-4]);
+ pr_cont("%s.\n", f15h_mc1_mce_desc[xec-4]);
break;
case 0x11 ... 0x14:
- pr_cont("Decoder %s parity error.\n", f15h_ic_mce_desc[xec-4]);
+ pr_cont("Decoder %s parity error.\n", f15h_mc1_mce_desc[xec-4]);
break;
default:
@@ -379,12 +379,12 @@ static bool f15h_ic_mce(u16 ec, u8 xec)
return ret;
}
-static void amd_decode_ic_mce(struct mce *m)
+static void decode_mc1_mce(struct mce *m)
{
u16 ec = EC(m->status);
u8 xec = XEC(m->status, xec_mask);
- pr_emerg(HW_ERR "Instruction Cache Error: ");
+ pr_emerg(HW_ERR "MC1 Error: ");
if (TLB_ERROR(ec))
pr_cont("%s TLB %s.\n", LL_MSG(ec),
@@ -393,18 +393,18 @@ static void amd_decode_ic_mce(struct mce *m)
bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
- } else if (fam_ops->ic_mce(ec, xec))
+ } else if (fam_ops->mc1_mce(ec, xec))
;
else
- pr_emerg(HW_ERR "Corrupted IC MCE info?\n");
+ pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n");
}
-static void amd_decode_bu_mce(struct mce *m)
+static void decode_mc2_mce(struct mce *m)
{
u16 ec = EC(m->status);
u8 xec = XEC(m->status, xec_mask);
- pr_emerg(HW_ERR "Bus Unit Error");
+ pr_emerg(HW_ERR "MC2 Error");
if (xec == 0x1)
pr_cont(" in the write data buffers.\n");
@@ -429,24 +429,24 @@ static void amd_decode_bu_mce(struct mce *m)
pr_cont(": %s parity/ECC error during data "
"access from L2.\n", R4_MSG(ec));
else
- goto wrong_bu_mce;
+ goto wrong_mc2_mce;
} else
- goto wrong_bu_mce;
+ goto wrong_mc2_mce;
} else
- goto wrong_bu_mce;
+ goto wrong_mc2_mce;
return;
-wrong_bu_mce:
- pr_emerg(HW_ERR "Corrupted BU MCE info?\n");
+ wrong_mc2_mce:
+ pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n");
}
-static void amd_decode_cu_mce(struct mce *m)
+static void decode_f15_mc2_mce(struct mce *m)
{
u16 ec = EC(m->status);
u8 xec = XEC(m->status, xec_mask);
- pr_emerg(HW_ERR "Combined Unit Error: ");
+ pr_emerg(HW_ERR "MC2 Error: ");
if (TLB_ERROR(ec)) {
if (xec == 0x0)
@@ -454,63 +454,63 @@ static void amd_decode_cu_mce(struct mce *m)
else if (xec == 0x1)
pr_cont("Poison data provided for TLB fill.\n");
else
- goto wrong_cu_mce;
+ goto wrong_f15_mc2_mce;
} else if (BUS_ERROR(ec)) {
if (xec > 2)
- goto wrong_cu_mce;
+ goto wrong_f15_mc2_mce;
pr_cont("Error during attempted NB data read.\n");
} else if (MEM_ERROR(ec)) {
switch (xec) {
case 0x4 ... 0xc:
- pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x4]);
+ pr_cont("%s.\n", f15h_mc2_mce_desc[xec - 0x4]);
break;
case 0x10 ... 0x14:
- pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x7]);
+ pr_cont("%s.\n", f15h_mc2_mce_desc[xec - 0x7]);
break;
default:
- goto wrong_cu_mce;
+ goto wrong_f15_mc2_mce;
}
}
return;
-wrong_cu_mce:
- pr_emerg(HW_ERR "Corrupted CU MCE info?\n");
+ wrong_f15_mc2_mce:
+ pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n");
}
-static void amd_decode_ls_mce(struct mce *m)
+static void decode_mc3_mce(struct mce *m)
{
u16 ec = EC(m->status);
u8 xec = XEC(m->status, xec_mask);
if (boot_cpu_data.x86 >= 0x14) {
- pr_emerg("You shouldn't be seeing an LS MCE on this cpu family,"
+ pr_emerg("You shouldn't be seeing MC3 MCE on this cpu family,"
" please report on LKML.\n");
return;
}
- pr_emerg(HW_ERR "Load Store Error");
+ pr_emerg(HW_ERR "MC3 Error");
if (xec == 0x0) {
u8 r4 = R4(ec);
if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR))
- goto wrong_ls_mce;
+ goto wrong_mc3_mce;
pr_cont(" during %s.\n", R4_MSG(ec));
} else
- goto wrong_ls_mce;
+ goto wrong_mc3_mce;
return;
-wrong_ls_mce:
- pr_emerg(HW_ERR "Corrupted LS MCE info?\n");
+ wrong_mc3_mce:
+ pr_emerg(HW_ERR "Corrupted MC3 MCE info?\n");
}
-void amd_decode_nb_mce(struct mce *m)
+static void decode_mc4_mce(struct mce *m)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
int node_id = amd_get_nb_id(m->extcpu);
@@ -518,7 +518,7 @@ void amd_decode_nb_mce(struct mce *m)
u8 xec = XEC(m->status, 0x1f);
u8 offset = 0;
- pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id);
+ pr_emerg(HW_ERR "MC4 Error (node %d): ", node_id);
switch (xec) {
case 0x0 ... 0xe:
@@ -527,9 +527,9 @@ void amd_decode_nb_mce(struct mce *m)
if (xec == 0x0 || xec == 0x8) {
/* no ECCs on F11h */
if (c->x86 == 0x11)
- goto wrong_nb_mce;
+ goto wrong_mc4_mce;
- pr_cont("%s.\n", nb_mce_desc[xec]);
+ pr_cont("%s.\n", mc4_mce_desc[xec]);
if (nb_bus_decoder)
nb_bus_decoder(node_id, m);
@@ -543,14 +543,14 @@ void amd_decode_nb_mce(struct mce *m)
else if (BUS_ERROR(ec))
pr_cont("DMA Exclusion Vector Table Walk error.\n");
else
- goto wrong_nb_mce;
+ goto wrong_mc4_mce;
return;
case 0x19:
if (boot_cpu_data.x86 == 0x15)
pr_cont("Compute Unit Data Error.\n");
else
- goto wrong_nb_mce;
+ goto wrong_mc4_mce;
return;
case 0x1c ... 0x1f:
@@ -558,46 +558,44 @@ void amd_decode_nb_mce(struct mce *m)
break;
default:
- goto wrong_nb_mce;
+ goto wrong_mc4_mce;
}
- pr_cont("%s.\n", nb_mce_desc[xec - offset]);
+ pr_cont("%s.\n", mc4_mce_desc[xec - offset]);
return;
-wrong_nb_mce:
- pr_emerg(HW_ERR "Corrupted NB MCE info?\n");
+ wrong_mc4_mce:
+ pr_emerg(HW_ERR "Corrupted MC4 MCE info?\n");
}
-EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
-static void amd_decode_fr_mce(struct mce *m)
+static void decode_mc5_mce(struct mce *m)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
u8 xec = XEC(m->status, xec_mask);
if (c->x86 == 0xf || c->x86 == 0x11)
- goto wrong_fr_mce;
+ goto wrong_mc5_mce;
- pr_emerg(HW_ERR "%s Error: ",
- (c->x86 == 0x15 ? "Execution Unit" : "FIROB"));
+ pr_emerg(HW_ERR "MC5 Error: ");
if (xec == 0x0 || xec == 0xc)
- pr_cont("%s.\n", fr_ex_mce_desc[xec]);
+ pr_cont("%s.\n", mc5_mce_desc[xec]);
else if (xec < 0xd)
- pr_cont("%s parity error.\n", fr_ex_mce_desc[xec]);
+ pr_cont("%s parity error.\n", mc5_mce_desc[xec]);
else
- goto wrong_fr_mce;
+ goto wrong_mc5_mce;
return;
-wrong_fr_mce:
- pr_emerg(HW_ERR "Corrupted FR MCE info?\n");
+ wrong_mc5_mce:
+ pr_emerg(HW_ERR "Corrupted MC5 MCE info?\n");
}
-static void amd_decode_fp_mce(struct mce *m)
+static void decode_mc6_mce(struct mce *m)
{
u8 xec = XEC(m->status, xec_mask);
- pr_emerg(HW_ERR "Floating Point Unit Error: ");
+ pr_emerg(HW_ERR "MC6 Error: ");
switch (xec) {
case 0x1:
@@ -621,7 +619,7 @@ static void amd_decode_fp_mce(struct mce *m)
break;
default:
- goto wrong_fp_mce;
+ goto wrong_mc6_mce;
break;
}
@@ -629,8 +627,8 @@ static void amd_decode_fp_mce(struct mce *m)
return;
-wrong_fp_mce:
- pr_emerg(HW_ERR "Corrupted FP MCE info?\n");
+ wrong_mc6_mce:
+ pr_emerg(HW_ERR "Corrupted MC6 MCE info?\n");
}
static inline void amd_decode_err_code(u16 ec)
@@ -669,74 +667,94 @@ static bool amd_filter_mce(struct mce *m)
return false;
}
+static const char *decode_error_status(struct mce *m)
+{
+ if (m->status & MCI_STATUS_UC) {
+ if (m->status & MCI_STATUS_PCC)
+ return "System Fatal error.";
+ if (m->mcgstatus & MCG_STATUS_RIPV)
+ return "Uncorrected, software restartable error.";
+ return "Uncorrected, software containable error.";
+ }
+
+ if (m->status & MCI_STATUS_DEFERRED)
+ return "Deferred error.";
+
+ return "Corrected error, no action required.";
+}
+
int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
{
struct mce *m = (struct mce *)data;
- struct cpuinfo_x86 *c = &boot_cpu_data;
+ struct cpuinfo_x86 *c = &cpu_data(m->extcpu);
int ecc;
if (amd_filter_mce(m))
return NOTIFY_STOP;
- pr_emerg(HW_ERR "CPU:%d\tMC%d_STATUS[%s|%s|%s|%s|%s",
- m->extcpu, m->bank,
- ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
- ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
- ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
- ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
- ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
-
- if (c->x86 == 0x15)
- pr_cont("|%s|%s",
- ((m->status & BIT_64(44)) ? "Deferred" : "-"),
- ((m->status & BIT_64(43)) ? "Poison" : "-"));
-
- /* do the two bits[14:13] together */
- ecc = (m->status >> 45) & 0x3;
- if (ecc)
- pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
-
- pr_cont("]: 0x%016llx\n", m->status);
-
- if (m->status & MCI_STATUS_ADDRV)
- pr_emerg(HW_ERR "\tMC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
-
switch (m->bank) {
case 0:
- amd_decode_dc_mce(m);
+ decode_mc0_mce(m);
break;
case 1:
- amd_decode_ic_mce(m);
+ decode_mc1_mce(m);
break;
case 2:
if (c->x86 == 0x15)
- amd_decode_cu_mce(m);
+ decode_f15_mc2_mce(m);
else
- amd_decode_bu_mce(m);
+ decode_mc2_mce(m);
break;
case 3:
- amd_decode_ls_mce(m);
+ decode_mc3_mce(m);
break;
case 4:
- amd_decode_nb_mce(m);
+ decode_mc4_mce(m);
break;
case 5:
- amd_decode_fr_mce(m);
+ decode_mc5_mce(m);
break;
case 6:
- amd_decode_fp_mce(m);
+ decode_mc6_mce(m);
break;
default:
break;
}
+ pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m));
+
+ pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s",
+ m->extcpu,
+ c->x86, c->x86_model, c->x86_mask,
+ m->bank,
+ ((m->status & MCI_STATUS_OVER) ? "Over" : "-"),
+ ((m->status & MCI_STATUS_UC) ? "UE" : "CE"),
+ ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"),
+ ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"),
+ ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-"));
+
+ if (c->x86 == 0x15)
+ pr_cont("|%s|%s",
+ ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"),
+ ((m->status & MCI_STATUS_POISON) ? "Poison" : "-"));
+
+ /* do the two bits[14:13] together */
+ ecc = (m->status >> 45) & 0x3;
+ if (ecc)
+ pr_cont("|%sECC", ((ecc == 2) ? "C" : "U"));
+
+ pr_cont("]: 0x%016llx\n", m->status);
+
+ if (m->status & MCI_STATUS_ADDRV)
+ pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
+
amd_decode_err_code(m->status & 0xffff);
return NOTIFY_STOP;
@@ -763,35 +781,35 @@ static int __init mce_amd_init(void)
switch (c->x86) {
case 0xf:
- fam_ops->dc_mce = k8_dc_mce;
- fam_ops->ic_mce = k8_ic_mce;
+ fam_ops->mc0_mce = k8_mc0_mce;
+ fam_ops->mc1_mce = k8_mc1_mce;
break;
case 0x10:
- fam_ops->dc_mce = f10h_dc_mce;
- fam_ops->ic_mce = k8_ic_mce;
+ fam_ops->mc0_mce = f10h_mc0_mce;
+ fam_ops->mc1_mce = k8_mc1_mce;
break;
case 0x11:
- fam_ops->dc_mce = k8_dc_mce;
- fam_ops->ic_mce = k8_ic_mce;
+ fam_ops->mc0_mce = k8_mc0_mce;
+ fam_ops->mc1_mce = k8_mc1_mce;
break;
case 0x12:
- fam_ops->dc_mce = f12h_dc_mce;
- fam_ops->ic_mce = k8_ic_mce;
+ fam_ops->mc0_mce = f12h_mc0_mce;
+ fam_ops->mc1_mce = k8_mc1_mce;
break;
case 0x14:
nb_err_cpumask = 0x3;
- fam_ops->dc_mce = f14h_dc_mce;
- fam_ops->ic_mce = f14h_ic_mce;
+ fam_ops->mc0_mce = f14h_mc0_mce;
+ fam_ops->mc1_mce = f14h_mc1_mce;
break;
case 0x15:
xec_mask = 0x1f;
- fam_ops->dc_mce = f15h_dc_mce;
- fam_ops->ic_mce = f15h_ic_mce;
+ fam_ops->mc0_mce = f15h_mc0_mce;
+ fam_ops->mc1_mce = f15h_mc1_mce;
break;
default:
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 8c87a5e87057..679679951e23 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -29,10 +29,8 @@
#define R4(x) (((x) >> 4) & 0xf)
#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!")
-/*
- * F3x4C bits (MCi_STATUS' high half)
- */
-#define NBSH_ERR_CPU_VAL BIT(24)
+#define MCI_STATUS_DEFERRED BIT_64(44)
+#define MCI_STATUS_POISON BIT_64(43)
enum tt_ids {
TT_INSTR = 0,
@@ -78,14 +76,13 @@ extern const char * const ii_msgs[];
* per-family decoder ops
*/
struct amd_decoder_ops {
- bool (*dc_mce)(u16, u8);
- bool (*ic_mce)(u16, u8);
+ bool (*mc0_mce)(u16, u8);
+ bool (*mc1_mce)(u16, u8);
};
void amd_report_gart_errors(bool);
void amd_register_ecc_decoder(void (*f)(int, struct mce *));
void amd_unregister_ecc_decoder(void (*f)(int, struct mce *));
-void amd_decode_nb_mce(struct mce *);
int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data);
#endif /* _EDAC_MCE_AMD_H */
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 66b5151c1080..2ae78f20cc28 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -6,7 +6,7 @@
* This file may be distributed under the terms of the GNU General Public
* License version 2.
*
- * Copyright (c) 2010: Borislav Petkov <borislav.petkov@amd.com>
+ * Copyright (c) 2010: Borislav Petkov <bp@alien8.de>
* Advanced Micro Devices Inc.
*/
@@ -168,6 +168,6 @@ module_init(edac_init_mce_inject);
module_exit(edac_exit_mce_inject);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>");
+MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>");
MODULE_AUTHOR("AMD Inc.");
MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding");
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 1162d6b3bf85..bb1b392f5cda 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1546,6 +1546,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
struct sbp2_logical_unit *lu = sdev->hostdata;
sdev->use_10_for_rw = 1;
+ sdev->no_report_opcodes = 1;
+ sdev->no_write_same = 1;
if (sbp2_param_exclusive_login)
sdev->manage_start_stop = 1;
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index f11d8e3b4041..47150f5ded04 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -466,7 +466,7 @@ config GPIO_ADP5588_IRQ
config GPIO_ADNP
tristate "Avionic Design N-bit GPIO expander"
- depends on I2C && OF
+ depends on I2C && OF_GPIO
help
This option enables support for N GPIOs found on Avionic Design
I2C GPIO expanders. The register space will be extended by powers
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index 0f425189de11..ce1c84760076 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -77,7 +77,7 @@ struct mcp23s08_driver_data {
/*----------------------------------------------------------------------*/
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg)
{
@@ -399,7 +399,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
break;
#endif /* CONFIG_SPI_MASTER */
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
case MCP_TYPE_008:
mcp->ops = &mcp23008_ops;
mcp->chip.ngpio = 8;
@@ -473,7 +473,7 @@ fail:
/*----------------------------------------------------------------------*/
-#ifdef CONFIG_I2C
+#if IS_ENABLED(CONFIG_I2C)
static int __devinit mcp230xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index cf7afb9eb61a..be65c0451ad5 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -92,6 +92,11 @@ static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip)
return mvchip->membase + GPIO_OUT_OFF;
}
+static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
+{
+ return mvchip->membase + GPIO_BLINK_EN_OFF;
+}
+
static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
{
return mvchip->membase + GPIO_IO_CONF_OFF;
@@ -206,6 +211,23 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin)
return (u >> pin) & 1;
}
+static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value)
+{
+ struct mvebu_gpio_chip *mvchip =
+ container_of(chip, struct mvebu_gpio_chip, chip);
+ unsigned long flags;
+ u32 u;
+
+ spin_lock_irqsave(&mvchip->lock, flags);
+ u = readl_relaxed(mvebu_gpioreg_blink(mvchip));
+ if (value)
+ u |= 1 << pin;
+ else
+ u &= ~(1 << pin);
+ writel_relaxed(u, mvebu_gpioreg_blink(mvchip));
+ spin_unlock_irqrestore(&mvchip->lock, flags);
+}
+
static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
{
struct mvebu_gpio_chip *mvchip =
@@ -244,6 +266,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
if (ret)
return ret;
+ mvebu_gpio_blink(chip, pin, 0);
mvebu_gpio_set(chip, pin, value);
spin_lock_irqsave(&mvchip->lock, flags);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index f1a45997aea8..d542a141811a 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -19,6 +19,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
/* Private data structure for of_gpiochip_find_and_xlate */
@@ -216,6 +217,54 @@ err0:
}
EXPORT_SYMBOL(of_mm_gpiochip_add);
+#ifdef CONFIG_PINCTRL
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
+{
+ struct device_node *np = chip->of_node;
+ struct of_phandle_args pinspec;
+ struct pinctrl_dev *pctldev;
+ int index = 0, ret;
+
+ if (!np)
+ return;
+
+ do {
+ ret = of_parse_phandle_with_args(np, "gpio-ranges",
+ "#gpio-range-cells", index, &pinspec);
+ if (ret)
+ break;
+
+ pctldev = of_pinctrl_get(pinspec.np);
+ 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_name(pctldev),
+ 0, /* offset in gpiochip */
+ pinspec.args[0],
+ pinspec.args[1]);
+
+ if (ret)
+ break;
+
+ } while (index++);
+}
+
+#else
+static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {}
+#endif
+
void of_gpiochip_add(struct gpio_chip *chip)
{
if ((!chip->of_node) && (chip->dev))
@@ -229,11 +278,14 @@ void of_gpiochip_add(struct gpio_chip *chip)
chip->of_xlate = of_gpio_simple_xlate;
}
+ of_gpiochip_add_pin_range(chip);
of_node_get(chip->of_node);
}
void of_gpiochip_remove(struct gpio_chip *chip)
{
+ gpiochip_remove_pin_ranges(chip);
+
if (chip->of_node)
of_node_put(chip->of_node);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 1c8d9e3380e1..58b9838801c0 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1083,6 +1083,10 @@ int gpiochip_add(struct gpio_chip *chip)
}
}
+#ifdef CONFIG_PINCTRL
+ INIT_LIST_HEAD(&chip->pin_ranges);
+#endif
+
of_gpiochip_add(chip);
unlock:
@@ -1123,6 +1127,7 @@ int gpiochip_remove(struct gpio_chip *chip)
spin_lock_irqsave(&gpio_lock, flags);
+ gpiochip_remove_pin_ranges(chip);
of_gpiochip_remove(chip);
for (id = chip->base; id < chip->base + chip->ngpio; id++) {
@@ -1180,6 +1185,77 @@ struct gpio_chip *gpiochip_find(void *data,
}
EXPORT_SYMBOL_GPL(gpiochip_find);
+#ifdef CONFIG_PINCTRL
+
+/**
+ * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping
+ * @chip: the gpiochip to add the range for
+ * @pinctrl_name: the dev_name() of the pin controller to map to
+ * @gpio_offset: the start offset in the current gpio_chip number space
+ * @pin_offset: the start offset in the pin controller number space
+ * @npins: the number of pins from the offset of each pin space (GPIO and
+ * pin controller) to accumulate in this range
+ */
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int gpio_offset, unsigned int pin_offset,
+ unsigned int npins)
+{
+ struct gpio_pin_range *pin_range;
+ int ret;
+
+ pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL);
+ if (!pin_range) {
+ pr_err("%s: GPIO chip: failed to allocate pin ranges\n",
+ chip->label);
+ return -ENOMEM;
+ }
+
+ /* Use local offset as range ID */
+ pin_range->range.id = gpio_offset;
+ pin_range->range.gc = chip;
+ pin_range->range.name = chip->label;
+ pin_range->range.base = chip->base + gpio_offset;
+ pin_range->range.pin_base = pin_offset;
+ pin_range->range.npins = npins;
+ pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name,
+ &pin_range->range);
+ if (IS_ERR(pin_range->pctldev)) {
+ ret = PTR_ERR(pin_range->pctldev);
+ pr_err("%s: GPIO chip: could not create pin range\n",
+ chip->label);
+ kfree(pin_range);
+ return ret;
+ }
+ pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n",
+ chip->label, gpio_offset, gpio_offset + npins - 1,
+ pinctl_name,
+ pin_offset, pin_offset + npins - 1);
+
+ list_add_tail(&pin_range->node, &chip->pin_ranges);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiochip_add_pin_range);
+
+/**
+ * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings
+ * @chip: the chip to remove all the mappings for
+ */
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+ struct gpio_pin_range *pin_range, *tmp;
+
+ list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) {
+ list_del(&pin_range->node);
+ pinctrl_remove_gpio_range(pin_range->pctldev,
+ &pin_range->range);
+ kfree(pin_range);
+ }
+}
+EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges);
+
+#endif /* CONFIG_PINCTRL */
+
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
* They're called even less than the "set direction" calls.
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 241ad1eeec64..f2df06c603f7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -226,6 +226,12 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
* already updated or not by exynos_drm_encoder_dpms function.
*/
exynos_encoder->updated = true;
+
+ /*
+ * In case of setcrtc, there is no way to update encoder's dpms
+ * so update it here.
+ */
+ exynos_encoder->dpms = DRM_MODE_DPMS_ON;
}
static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
@@ -507,6 +513,6 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
* because the setting for disabling the overlay will be updated
* at vsync.
*/
- if (overlay_ops->wait_for_vblank)
+ if (overlay_ops && overlay_ops->wait_for_vblank)
overlay_ops->wait_for_vblank(manager->dev);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 67eb6ba56edf..e7466c4414cb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -87,7 +87,8 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr;
fbi->screen_base = buffer->kvaddr + offset;
- fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset);
+ fbi->fix.smem_start = (unsigned long)(page_to_phys(buffer->pages[0]) +
+ offset);
fbi->screen_size = size;
fbi->fix.smem_len = size;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 130a2b510d4a..e08478f19f1a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -61,11 +61,11 @@ struct fimd_driver_data {
unsigned int timing_base;
};
-struct fimd_driver_data exynos4_fimd_driver_data = {
+static struct fimd_driver_data exynos4_fimd_driver_data = {
.timing_base = 0x0,
};
-struct fimd_driver_data exynos5_fimd_driver_data = {
+static struct fimd_driver_data exynos5_fimd_driver_data = {
.timing_base = 0x20000,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index 60b877a388c2..862ca1eb2102 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -204,7 +204,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
return ret;
plane->crtc = crtc;
- plane->fb = crtc->fb;
exynos_plane_commit(plane);
exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 107f09befe92..9b285da4449b 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1796,7 +1796,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
*/
mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
gfp = mapping_gfp_mask(mapping);
- gfp |= __GFP_NORETRY | __GFP_NOWARN;
+ gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
gfp &= ~(__GFP_IO | __GFP_WAIT);
for_each_sg(st->sgl, sg, page_count, i) {
page = shmem_read_mapping_page_gfp(mapping, i, gfp);
@@ -1809,7 +1809,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
* our own buffer, now let the real VM do its job and
* go down in flames if truly OOM.
*/
- gfp &= ~(__GFP_NORETRY | __GFP_NOWARN);
+ gfp &= ~(__GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD);
gfp |= __GFP_IO | __GFP_WAIT;
i915_gem_shrink_all(dev_priv);
@@ -1817,7 +1817,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
if (IS_ERR(page))
goto err_pages;
- gfp |= __GFP_NORETRY | __GFP_NOWARN;
+ gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD;
gfp &= ~(__GFP_IO | __GFP_WAIT);
}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 0ed6baff4b0c..56846ed5ee55 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -499,12 +499,8 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
edp = find_section(bdb, BDB_EDP);
if (!edp) {
- if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) {
- DRM_DEBUG_KMS("No eDP BDB found but eDP panel "
- "supported, assume %dbpp panel color "
- "depth.\n",
- dev_priv->edp.bpp);
- }
+ if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support)
+ DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n");
return;
}
@@ -657,9 +653,6 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
dev_priv->lvds_use_ssc = 1;
dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1);
DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq);
-
- /* eDP data */
- dev_priv->edp.bpp = 18;
}
static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index b726b478a4f5..6345878ae1e7 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -143,7 +143,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
int old_dpms;
/* PCH platforms and VLV only support on/off. */
- if (INTEL_INFO(dev)->gen < 5 && mode != DRM_MODE_DPMS_ON)
+ if (INTEL_INFO(dev)->gen >= 5 && mode != DRM_MODE_DPMS_ON)
mode = DRM_MODE_DPMS_OFF;
if (mode == connector->dpms)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 461a637f1ef7..b426d44a2b05 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3841,6 +3841,17 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
}
}
+ if (intel_encoder->type == INTEL_OUTPUT_EDP) {
+ /* Use VBT settings if we have an eDP panel */
+ unsigned int edp_bpc = dev_priv->edp.bpp / 3;
+
+ if (edp_bpc && edp_bpc < display_bpc) {
+ DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
+ display_bpc = edp_bpc;
+ }
+ continue;
+ }
+
/*
* HDMI is either 12 or 8, so if the display lets 10bpc sneak
* through, clamp it down. (Note: >12bpc will be caught below.)
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 72f41aaa71ff..442968f8b201 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2373,15 +2373,9 @@ int intel_enable_rc6(const struct drm_device *dev)
if (i915_enable_rc6 >= 0)
return i915_enable_rc6;
- if (INTEL_INFO(dev)->gen == 5) {
-#ifdef CONFIG_INTEL_IOMMU
- /* Disable rc6 on ilk if VT-d is on. */
- if (intel_iommu_gfx_mapped)
- return false;
-#endif
- DRM_DEBUG_DRIVER("Ironlake: only RC6 available\n");
- return INTEL_RC6_ENABLE;
- }
+ /* Disable RC6 on Ironlake */
+ if (INTEL_INFO(dev)->gen == 5)
+ return 0;
if (IS_HASWELL(dev)) {
DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 79d308da29ff..a6ac0b416964 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2201,7 +2201,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
intel_sdvo->is_hdmi = true;
}
- intel_sdvo->base.cloneable = true;
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
if (intel_sdvo->is_hdmi)
@@ -2232,7 +2231,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
intel_sdvo->is_tv = true;
intel_sdvo->base.needs_tv_clock = true;
- intel_sdvo->base.cloneable = false;
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
@@ -2275,8 +2273,6 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
}
- intel_sdvo->base.cloneable = true;
-
intel_sdvo_connector_init(intel_sdvo_connector,
intel_sdvo);
return true;
@@ -2307,9 +2303,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
}
- /* SDVO LVDS is not cloneable because the input mode gets adjusted by the encoder */
- intel_sdvo->base.cloneable = false;
-
intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
goto err;
@@ -2382,6 +2375,18 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
return true;
}
+static void intel_sdvo_output_cleanup(struct intel_sdvo *intel_sdvo)
+{
+ struct drm_device *dev = intel_sdvo->base.base.dev;
+ struct drm_connector *connector, *tmp;
+
+ list_for_each_entry_safe(connector, tmp,
+ &dev->mode_config.connector_list, head) {
+ if (intel_attached_encoder(connector) == &intel_sdvo->base)
+ intel_sdvo_destroy(connector);
+ }
+}
+
static bool intel_sdvo_tv_create_property(struct intel_sdvo *intel_sdvo,
struct intel_sdvo_connector *intel_sdvo_connector,
int type)
@@ -2705,9 +2710,20 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
intel_sdvo->caps.output_flags) != true) {
DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
SDVO_NAME(intel_sdvo));
- goto err;
+ /* Output_setup can leave behind connectors! */
+ goto err_output;
}
+ /*
+ * Cloning SDVO with anything is often impossible, since the SDVO
+ * encoder can request a special input timing mode. And even if that's
+ * not the case we have evidence that cloning a plain unscaled mode with
+ * VGA doesn't really work. Furthermore the cloning flags are way too
+ * simplistic anyway to express such constraints, so just give up on
+ * cloning for SDVO encoders.
+ */
+ intel_sdvo->base.cloneable = false;
+
/* Only enable the hotplug irq if we need it, to work around noisy
* hotplug lines.
*/
@@ -2718,12 +2734,12 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
/* Set the input timing to the screen. Assume always input 0. */
if (!intel_sdvo_set_target_input(intel_sdvo))
- goto err;
+ goto err_output;
if (!intel_sdvo_get_input_pixel_clock_range(intel_sdvo,
&intel_sdvo->pixel_clock_min,
&intel_sdvo->pixel_clock_max))
- goto err;
+ goto err_output;
DRM_DEBUG_KMS("%s device VID/DID: %02X:%02X.%02X, "
"clock range %dMHz - %dMHz, "
@@ -2743,6 +2759,9 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
return true;
+err_output:
+ intel_sdvo_output_cleanup(intel_sdvo);
+
err:
drm_encoder_cleanup(&intel_encoder->base);
i2c_del_adapter(&intel_sdvo->ddc);
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
index 05a909a17cee..15b182c84ce8 100644
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
@@ -49,13 +49,7 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
if (chan->vblank.crtc != crtc)
continue;
- if (nv_device(priv)->chipset == 0x50) {
- nv_wr32(priv, 0x001704, chan->vblank.channel);
- nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
- bar->flush(bar);
- nv_wr32(priv, 0x001570, chan->vblank.offset);
- nv_wr32(priv, 0x001574, chan->vblank.value);
- } else {
+ if (nv_device(priv)->chipset >= 0xc0) {
nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
bar->flush(bar);
nv_wr32(priv, 0x06000c,
@@ -63,6 +57,17 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc)
nv_wr32(priv, 0x060010,
lower_32_bits(chan->vblank.offset));
nv_wr32(priv, 0x060014, chan->vblank.value);
+ } else {
+ nv_wr32(priv, 0x001704, chan->vblank.channel);
+ nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
+ bar->flush(bar);
+ if (nv_device(priv)->chipset == 0x50) {
+ nv_wr32(priv, 0x001570, chan->vblank.offset);
+ nv_wr32(priv, 0x001574, chan->vblank.value);
+ } else {
+ nv_wr32(priv, 0x060010, chan->vblank.offset);
+ nv_wr32(priv, 0x060014, chan->vblank.value);
+ }
}
list_del(&chan->vblank.head);
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
index e45035efb8ca..7bbb1e1b7a8d 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
@@ -669,21 +669,27 @@ nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
});
}
-void
+int
nv40_grctx_init(struct nouveau_device *device, u32 *size)
{
- u32 ctxprog[256], i;
+ u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i;
struct nouveau_grctx ctx = {
.device = device,
.mode = NOUVEAU_GRCTX_PROG,
.data = ctxprog,
- .ctxprog_max = ARRAY_SIZE(ctxprog)
+ .ctxprog_max = 256,
};
+ if (!ctxprog)
+ return -ENOMEM;
+
nv40_grctx_generate(&ctx);
nv_wr32(device, 0x400324, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
nv_wr32(device, 0x400328, ctxprog[i]);
*size = ctx.ctxvals_pos * 4;
+
+ kfree(ctxprog);
+ return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
index 425001204a89..cc6574eeb80e 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
@@ -346,7 +346,9 @@ nv40_graph_init(struct nouveau_object *object)
return ret;
/* generate and upload context program */
- nv40_grctx_init(nv_device(priv), &priv->size);
+ ret = nv40_grctx_init(nv_device(priv), &priv->size);
+ if (ret)
+ return ret;
/* No context present currently */
nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
index d2ac975afc2e..7da35a4e7970 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
+++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
@@ -15,7 +15,7 @@ nv44_graph_class(void *priv)
return !(0x0baf & (1 << (device->chipset & 0x0f)));
}
-void nv40_grctx_init(struct nouveau_device *, u32 *size);
+int nv40_grctx_init(struct nouveau_device *, u32 *size);
void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h
index 818feabbf4a0..486f1a9217fd 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/object.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/object.h
@@ -175,14 +175,18 @@ nv_mo32(void *obj, u32 addr, u32 mask, u32 data)
return temp;
}
-static inline bool
-nv_strncmp(void *obj, u32 addr, u32 len, const char *str)
+static inline int
+nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
{
+ unsigned char c1, c2;
+
while (len--) {
- if (nv_ro08(obj, addr++) != *(str++))
- return false;
+ c1 = nv_ro08(obj, addr++);
+ c2 = *(str++);
+ if (c1 != c2)
+ return c1 - c2;
}
- return true;
+ return 0;
}
#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
index 39e73b91d360..41b7a6a76f19 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
+++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
@@ -54,6 +54,7 @@ int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
int clk, struct nouveau_pll_vals *);
int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,
struct nouveau_pll_vals *);
-
+int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
+ int clk, struct nouveau_pll_vals *);
#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
index 7d750382a833..c51197157749 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
@@ -64,7 +64,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
}
} else
if (*ver >= 0x15) {
- if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) {
+ if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) {
u16 i2c = nv_ro16(bios, dcb + 2);
*hdr = 4;
*cnt = (i2c - dcb) / 10;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
index cc8d7d162d7c..9068c98b96f6 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
@@ -66,6 +66,24 @@ nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq)
return ret;
}
+int
+nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
+ int clk, struct nouveau_pll_vals *pv)
+{
+ int ret, N, M, P;
+
+ ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P);
+
+ if (ret > 0) {
+ pv->refclk = info->refclk;
+ pv->N1 = N;
+ pv->M1 = M;
+ pv->log2P = P;
+ }
+ return ret;
+}
+
+
static int
nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
struct nouveau_oclass *oclass, void *data, u32 size,
@@ -80,6 +98,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.pll_set = nva3_clock_pll_set;
+ priv->base.pll_calc = nva3_clock_pll_calc;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
index 5ccce0b17bf3..f6962c9b6c36 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
@@ -79,6 +79,7 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
return ret;
priv->base.pll_set = nvc0_clock_pll_set;
+ priv->base.pll_calc = nva3_clock_pll_calc;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index cc79c796afee..cbf1fc60a386 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -241,6 +241,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
if (unlikely(!abi16))
return -ENOMEM;
+
+ if (!drm->channel)
+ return nouveau_abi16_put(abi16, -ENODEV);
+
client = nv_client(abi16->client);
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 0910125cbbc3..8503b2ea570a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -129,7 +129,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
/* initialise synchronisation routines */
if (device->card_type < NV_10) ret = nv04_fence_create(drm);
- else if (device->chipset < 0x84) ret = nv10_fence_create(drm);
+ else if (device->card_type < NV_50) ret = nv10_fence_create(drm);
+ else if (device->chipset < 0x84) ret = nv50_fence_create(drm);
else if (device->card_type < NV_C0) ret = nv84_fence_create(drm);
else ret = nvc0_fence_create(drm);
if (ret) {
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 3bce0299f64a..24d932f53203 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1696,42 +1696,22 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
return ATOM_PPLL2;
DRM_ERROR("unable to allocate a PPLL\n");
return ATOM_PPLL_INVALID;
- } else if (ASIC_IS_AVIVO(rdev)) {
- /* in DP mode, the DP ref clock can come from either PPLL
- * depending on the asic:
- * DCE3: PPLL1 or PPLL2
- */
- if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) {
- /* use the same PPLL for all DP monitors */
- pll = radeon_get_shared_dp_ppll(crtc);
- if (pll != ATOM_PPLL_INVALID)
- return pll;
- } else {
- /* use the same PPLL for all monitors with the same clock */
- pll = radeon_get_shared_nondp_ppll(crtc);
- if (pll != ATOM_PPLL_INVALID)
- return pll;
- }
- /* all other cases */
- pll_in_use = radeon_get_pll_use_mask(crtc);
- /* the order shouldn't matter here, but we probably
- * need this until we have atomic modeset
- */
- if (rdev->flags & RADEON_IS_IGP) {
- if (!(pll_in_use & (1 << ATOM_PPLL1)))
- return ATOM_PPLL1;
- if (!(pll_in_use & (1 << ATOM_PPLL2)))
- return ATOM_PPLL2;
- } else {
- if (!(pll_in_use & (1 << ATOM_PPLL2)))
- return ATOM_PPLL2;
- if (!(pll_in_use & (1 << ATOM_PPLL1)))
- return ATOM_PPLL1;
- }
- DRM_ERROR("unable to allocate a PPLL\n");
- return ATOM_PPLL_INVALID;
} else {
/* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
+ /* some atombios (observed in some DCE2/DCE3) code have a bug,
+ * the matching btw pll and crtc is done through
+ * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the
+ * pll (1 or 2) to select which register to write. ie if using
+ * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2
+ * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to
+ * choose which value to write. Which is reverse order from
+ * register logic. So only case that works is when pllid is
+ * same as crtcid or when both pll and crtc are enabled and
+ * both use same clock.
+ *
+ * So just return crtc id as if crtc and pll were hard linked
+ * together even if they aren't
+ */
return radeon_crtc->crtc_id;
}
}
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index ba498f8e47a2..010bae19554a 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -1625,7 +1625,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
/* some early dce3.2 boards have a bug in their transmitter control table */
- if ((rdev->family != CHIP_RV710) || (rdev->family != CHIP_RV730))
+ if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730))
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
}
if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index af31f829f4a8..219942c660d7 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1330,6 +1330,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav
break;
udelay(1);
}
+ } else {
+ save->crtc_enabled[i] = false;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c
index 10ea17a6b2a6..42433344cb1b 100644
--- a/drivers/gpu/drm/radeon/radeon_agp.c
+++ b/drivers/gpu/drm/radeon/radeon_agp.c
@@ -69,9 +69,12 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {
/* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/
{ PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59,
PCI_VENDOR_ID_DELL, 0x00e3, 2},
- /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */
+ /* Intel 82852/82855 host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 (lp #296617) */
{ PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66,
PCI_VENDOR_ID_DELL, 0x0149, 1},
+ /* Intel 82855PM host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 for suspend/resume */
+ { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66,
+ PCI_VENDOR_ID_IBM, 0x0531, 1},
/* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */
{ PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50,
0x1025, 0x0061, 1},
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index 860dc4813e99..bd2a3b40cd12 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -749,7 +749,10 @@ static int ttm_get_pages(struct page **pages, unsigned npages, int flags,
/* clear the pages coming from the pool if requested */
if (flags & TTM_PAGE_FLAG_ZERO_ALLOC) {
list_for_each_entry(p, &plist, lru) {
- clear_page(page_address(p));
+ if (PageHighMem(p))
+ clear_highpage(p);
+ else
+ clear_page(page_address(p));
}
}
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index bf8260133ea9..7d759a430294 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -308,9 +308,7 @@ int ttm_tt_swapin(struct ttm_tt *ttm)
if (unlikely(to_page == NULL))
goto out_err;
- preempt_disable();
copy_highpage(to_page, from_page);
- preempt_enable();
page_cache_release(from_page);
}
@@ -358,9 +356,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
ret = PTR_ERR(to_page);
goto out_err;
}
- preempt_disable();
copy_highpage(to_page, from_page);
- preempt_enable();
set_page_dirty(to_page);
mark_page_accessed(to_page);
page_cache_release(to_page);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index b07ca2e4d04b..7290811f89be 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -110,6 +110,8 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
ret = copy_to_user(buffer, bounce, size);
+ if (ret)
+ ret = -EFAULT;
vfree(bounce);
if (unlikely(ret != 0))
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index f676c01bb471..6fcd466d0825 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -46,9 +46,9 @@ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[559] = 0x45;
}
/* the same as above (s/usage/physical/) */
- if ((quirks & MS_RDESC_3K) && *rsize == 106 &&
- !memcmp((char []){ 0x19, 0x00, 0x29, 0xff },
- &rdesc[94], 4)) {
+ if ((quirks & MS_RDESC_3K) && *rsize == 106 && rdesc[94] == 0x19 &&
+ rdesc[95] == 0x00 && rdesc[96] == 0x29 &&
+ rdesc[97] == 0xff) {
rdesc[94] = 0x35;
rdesc[96] = 0x45;
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index c4633de64465..4800d4c2a7b7 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -334,6 +334,16 @@ config SENSORS_DA9052_ADC
This driver can also be built as module. If so, the module
will be called da9052-hwmon.
+config SENSORS_DA9055
+ tristate "Dialog Semiconductor DA9055 ADC"
+ depends on MFD_DA9055
+ help
+ If you say yes here you get support for ADC on the Dialog
+ Semiconductor DA9055 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called da9055-hwmon.
+
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI
@@ -455,7 +465,7 @@ config SENSORS_HIH6130
config SENSORS_CORETEMP
tristate "Intel Core/Core2/Atom temperature sensor"
- depends on X86 && PCI
+ depends on X86
help
If you say yes here you get support for the temperature
sensor inside your CPU. Most of the family 6 CPUs
@@ -1106,11 +1116,12 @@ config SENSORS_ADS1015
will be called ads1015.
config SENSORS_ADS7828
- tristate "Texas Instruments ADS7828"
+ tristate "Texas Instruments ADS7828 and compatibles"
depends on I2C
help
- If you say yes here you get support for Texas Instruments ADS7828
- 12-bit 8-channel ADC device.
+ If you say yes here you get support for Texas Instruments ADS7828 and
+ ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while
+ it is 8-bit on ADS7830.
This driver can also be built as a module. If so, the module
will be called ads7828.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 8d5fcb5e8e9f..a930f0997d25 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
+obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 1f9e8af0f322..409b5c16defb 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -1,12 +1,14 @@
/*
- * ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC
+ * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles
* (C) 2007 EADS Astrium
*
* This driver is based on the lm75 and other lm_sensors/hwmon drivers
*
* Written by Steve Hardy <shardy@redhat.com>
*
- * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf
+ * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
+ *
+ * For further information, see the Documentation/hwmon/ads7828 file.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,63 +25,48 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/jiffies.h>
-#include <linux/i2c.h>
+#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/platform_data/ads7828.h>
+#include <linux/slab.h>
/* The ADS7828 registers */
-#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */
-#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
-#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */
-#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */
-#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */
-#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */
-#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */
-#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
-
-/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
- I2C_CLIENT_END };
-
-/* Module parameters */
-static bool se_input = 1; /* Default is SE, 0 == diff */
-static bool int_vref = 1; /* Default is internal ref ON */
-static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
-module_param(se_input, bool, S_IRUGO);
-module_param(int_vref, bool, S_IRUGO);
-module_param(vref_mv, int, S_IRUGO);
-
-/* Global Variables */
-static u8 ads7828_cmd_byte; /* cmd byte without channel bits */
-static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
-
-/* Each client has this additional data */
+#define ADS7828_NCH 8 /* 8 channels supported */
+#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
+#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */
+#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */
+#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
+#define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */
+#define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */
+
+/* List of supported devices */
+enum ads7828_chips { ads7828, ads7830 };
+
+/* Client specific data */
struct ads7828_data {
struct device *hwmon_dev;
- struct mutex update_lock; /* mutex protect updates */
- char valid; /* !=0 if following fields are valid */
- unsigned long last_updated; /* In jiffies */
- u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */
+ struct mutex update_lock; /* Mutex protecting updates */
+ unsigned long last_updated; /* Last updated time (in jiffies) */
+ u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
+ bool valid; /* Validity flag */
+ bool diff_input; /* Differential input */
+ bool ext_vref; /* External voltage reference */
+ unsigned int vref_mv; /* voltage reference value */
+ u8 cmd_byte; /* Command byte without channel bits */
+ unsigned int lsb_resol; /* Resolution of the ADC sample LSB */
+ s32 (*read_channel)(const struct i2c_client *client, u8 command);
};
-/* Function declaration - necessary due to function dependencies */
-static int ads7828_detect(struct i2c_client *client,
- struct i2c_board_info *info);
-static int ads7828_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
-
-static inline u8 channel_cmd_byte(int ch)
+/* Command byte C2,C1,C0 - see datasheet */
+static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
{
- /* cmd byte C2,C1,C0 - see datasheet */
- u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
- cmd |= ads7828_cmd_byte;
- return cmd;
+ return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
}
/* Update data for the device (all 8 channels) */
@@ -96,12 +83,11 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
dev_dbg(&client->dev, "Starting ads7828 update\n");
for (ch = 0; ch < ADS7828_NCH; ch++) {
- u8 cmd = channel_cmd_byte(ch);
- data->adc_input[ch] =
- i2c_smbus_read_word_swapped(client, cmd);
+ u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch);
+ data->adc_input[ch] = data->read_channel(client, cmd);
}
data->last_updated = jiffies;
- data->valid = 1;
+ data->valid = true;
}
mutex_unlock(&data->update_lock);
@@ -110,28 +96,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
}
/* sysfs callback function */
-static ssize_t show_in(struct device *dev, struct device_attribute *da,
- char *buf)
+static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct ads7828_data *data = ads7828_update_device(dev);
- /* Print value (in mV as specified in sysfs-interface documentation) */
- return sprintf(buf, "%d\n", (data->adc_input[attr->index] *
- ads7828_lsb_resol)/1000);
-}
+ unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
+ data->lsb_resol, 1000);
-#define in_reg(offset)\
-static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\
- NULL, offset)
+ return sprintf(buf, "%d\n", value);
+}
-in_reg(0);
-in_reg(1);
-in_reg(2);
-in_reg(3);
-in_reg(4);
-in_reg(5);
-in_reg(6);
-in_reg(7);
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
static struct attribute *ads7828_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
@@ -152,60 +135,9 @@ static const struct attribute_group ads7828_group = {
static int ads7828_remove(struct i2c_client *client)
{
struct ads7828_data *data = i2c_get_clientdata(client);
+
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
- return 0;
-}
-
-static const struct i2c_device_id ads7828_id[] = {
- { "ads7828", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ads7828_id);
-
-/* This is the driver that will be inserted */
-static struct i2c_driver ads7828_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "ads7828",
- },
- .probe = ads7828_probe,
- .remove = ads7828_remove,
- .id_table = ads7828_id,
- .detect = ads7828_detect,
- .address_list = normal_i2c,
-};
-
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int ads7828_detect(struct i2c_client *client,
- struct i2c_board_info *info)
-{
- struct i2c_adapter *adapter = client->adapter;
- int ch;
-
- /* Check we have a valid client */
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -ENODEV;
-
- /*
- * Now, we do the remaining detection. There is no identification
- * dedicated register so attempt to sanity check using knowledge of
- * the chip
- * - Read from the 8 channel addresses
- * - Check the top 4 bits of each result are not set (12 data bits)
- */
- for (ch = 0; ch < ADS7828_NCH; ch++) {
- u16 in_data;
- u8 cmd = channel_cmd_byte(ch);
- in_data = i2c_smbus_read_word_swapped(client, cmd);
- if (in_data & 0xF000) {
- pr_debug("%s : Doesn't look like an ads7828 device\n",
- __func__);
- return -ENODEV;
- }
- }
-
- strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
return 0;
}
@@ -213,6 +145,7 @@ static int ads7828_detect(struct i2c_client *client,
static int ads7828_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct ads7828_platform_data *pdata = client->dev.platform_data;
struct ads7828_data *data;
int err;
@@ -221,10 +154,37 @@ static int ads7828_probe(struct i2c_client *client,
if (!data)
return -ENOMEM;
+ if (pdata) {
+ data->diff_input = pdata->diff_input;
+ data->ext_vref = pdata->ext_vref;
+ if (data->ext_vref)
+ data->vref_mv = pdata->vref_mv;
+ }
+
+ /* Bound Vref with min/max values if it was provided */
+ if (data->vref_mv)
+ data->vref_mv = SENSORS_LIMIT(data->vref_mv,
+ ADS7828_EXT_VREF_MV_MIN,
+ ADS7828_EXT_VREF_MV_MAX);
+ else
+ data->vref_mv = ADS7828_INT_VREF_MV;
+
+ /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
+ if (id->driver_data == ads7828) {
+ data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096);
+ data->read_channel = i2c_smbus_read_word_swapped;
+ } else {
+ data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256);
+ data->read_channel = i2c_smbus_read_byte_data;
+ }
+
+ data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
+ if (!data->diff_input)
+ data->cmd_byte |= ADS7828_CMD_SD_SE;
+
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
- /* Register sysfs hooks */
err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
if (err)
return err;
@@ -232,38 +192,35 @@ static int ads7828_probe(struct i2c_client *client,
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
- goto exit_remove;
+ goto error;
}
return 0;
-exit_remove:
+error:
sysfs_remove_group(&client->dev.kobj, &ads7828_group);
return err;
}
-static int __init sensors_ads7828_init(void)
-{
- /* Initialize the command byte according to module parameters */
- ads7828_cmd_byte = se_input ?
- ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF;
- ads7828_cmd_byte |= int_vref ?
- ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
+static const struct i2c_device_id ads7828_device_ids[] = {
+ { "ads7828", ads7828 },
+ { "ads7830", ads7830 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
- /* Calculate the LSB resolution */
- ads7828_lsb_resol = (vref_mv*1000)/4096;
+static struct i2c_driver ads7828_driver = {
+ .driver = {
+ .name = "ads7828",
+ },
- return i2c_add_driver(&ads7828_driver);
-}
+ .id_table = ads7828_device_ids,
+ .probe = ads7828_probe,
+ .remove = ads7828_remove,
+};
-static void __exit sensors_ads7828_exit(void)
-{
- i2c_del_driver(&ads7828_driver);
-}
+module_i2c_driver(ads7828_driver);
-MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
-MODULE_DESCRIPTION("ADS7828 driver");
MODULE_LICENSE("GPL");
-
-module_init(sensors_ads7828_init);
-module_exit(sensors_ads7828_exit);
+MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
+MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 47b8d84b489d..24426a785ad5 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -34,7 +34,6 @@
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/cpu.h>
-#include <linux/pci.h>
#include <linux/smp.h>
#include <linux/moduleparam.h>
#include <asm/msr.h>
@@ -197,14 +196,6 @@ struct tjmax {
};
static const struct tjmax __cpuinitconst tjmax_table[] = {
- { "CPU D410", 100000 },
- { "CPU D425", 100000 },
- { "CPU D510", 100000 },
- { "CPU D525", 100000 },
- { "CPU N450", 100000 },
- { "CPU N455", 100000 },
- { "CPU N470", 100000 },
- { "CPU N475", 100000 },
{ "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */
{ "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */
{ "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */
@@ -212,6 +203,28 @@ static const struct tjmax __cpuinitconst tjmax_table[] = {
{ "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */
};
+struct tjmax_model {
+ u8 model;
+ u8 mask;
+ int tjmax;
+};
+
+#define ANY 0xff
+
+static const struct tjmax_model __cpuinitconst tjmax_model_table[] = {
+ { 0x1c, 10, 100000 }, /* D4xx, N4xx, D5xx, N5xx */
+ { 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others
+ * Note: Also matches 230 and 330,
+ * which are covered by tjmax_table
+ */
+ { 0x26, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx)
+ * Note: TjMax for E6xxT is 110C, but CPU type
+ * is undetectable by software
+ */
+ { 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */
+ { 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */
+};
+
static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
struct device *dev)
{
@@ -222,7 +235,6 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
int usemsr_ee = 1;
int err;
u32 eax, edx;
- struct pci_dev *host_bridge;
int i;
/* explicit tjmax table entries override heuristics */
@@ -231,32 +243,18 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id,
return tjmax_table[i].tjmax;
}
+ for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) {
+ const struct tjmax_model *tm = &tjmax_model_table[i];
+ if (c->x86_model == tm->model &&
+ (tm->mask == ANY || c->x86_mask == tm->mask))
+ return tm->tjmax;
+ }
+
/* Early chips have no MSR for TjMax */
if (c->x86_model == 0xf && c->x86_mask < 4)
usemsr_ee = 0;
- /* Atom CPUs */
-
- if (c->x86_model == 0x1c || c->x86_model == 0x26
- || c->x86_model == 0x27) {
- usemsr_ee = 0;
-
- host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0));
-
- if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL
- && (host_bridge->device == 0xa000 /* NM10 based nettop */
- || host_bridge->device == 0xa010)) /* NM10 based netbook */
- tjmax = 100000;
- else
- tjmax = 90000;
-
- pci_dev_put(host_bridge);
- } else if (c->x86_model == 0x36) {
- usemsr_ee = 0;
- tjmax = 100000;
- }
-
if (c->x86_model > 0xe && usemsr_ee) {
u8 platform_id;
diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c
index b8d01c5f5713..19704948801c 100644
--- a/drivers/hwmon/da9052-hwmon.c
+++ b/drivers/hwmon/da9052-hwmon.c
@@ -60,30 +60,17 @@ static inline int vbbat_reg_to_mV(int value)
return DIV_ROUND_CLOSEST(value * 2500, 512);
}
-static int da9052_enable_vddout_channel(struct da9052 *da9052)
+static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
{
- int ret;
-
- ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
- if (ret < 0)
- return ret;
-
- ret |= DA9052_ADCCONT_AUTOVDDEN;
-
- return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
+ return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
+ DA9052_ADCCONT_AUTOVDDEN,
+ DA9052_ADCCONT_AUTOVDDEN);
}
-static int da9052_disable_vddout_channel(struct da9052 *da9052)
+static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
{
- int ret;
-
- ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG);
- if (ret < 0)
- return ret;
-
- ret &= ~DA9052_ADCCONT_AUTOVDDEN;
-
- return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret);
+ return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
+ DA9052_ADCCONT_AUTOVDDEN, 0);
}
static ssize_t da9052_read_vddout(struct device *dev,
diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c
new file mode 100644
index 000000000000..9465c050c326
--- /dev/null
+++ b/drivers/hwmon/da9055-hwmon.c
@@ -0,0 +1,336 @@
+/*
+ * HWMON Driver for Dialog DA9055
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+#define DA9055_ADCIN_DIV 102
+#define DA9055_VSYS_DIV 85
+
+#define DA9055_ADC_VSYS 0
+#define DA9055_ADC_ADCIN1 1
+#define DA9055_ADC_ADCIN2 2
+#define DA9055_ADC_ADCIN3 3
+#define DA9055_ADC_TJUNC 4
+
+struct da9055_hwmon {
+ struct da9055 *da9055;
+ struct device *class_device;
+ struct mutex hwmon_lock;
+ struct mutex irq_lock;
+ struct completion done;
+};
+
+static const char * const input_names[] = {
+ [DA9055_ADC_VSYS] = "VSYS",
+ [DA9055_ADC_ADCIN1] = "ADC IN1",
+ [DA9055_ADC_ADCIN2] = "ADC IN2",
+ [DA9055_ADC_ADCIN3] = "ADC IN3",
+ [DA9055_ADC_TJUNC] = "CHIP TEMP",
+};
+
+static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = {
+ [DA9055_ADC_VSYS] = DA9055_ADC_MUX_VSYS,
+ [DA9055_ADC_ADCIN1] = DA9055_ADC_MUX_ADCIN1,
+ [DA9055_ADC_ADCIN2] = DA9055_ADC_MUX_ADCIN2,
+ [DA9055_ADC_ADCIN3] = DA9055_ADC_MUX_ADCIN3,
+ [DA9055_ADC_TJUNC] = DA9055_ADC_MUX_T_SENSE,
+};
+
+static int da9055_adc_manual_read(struct da9055_hwmon *hwmon,
+ unsigned char channel)
+{
+ int ret;
+ unsigned short calc_data;
+ unsigned short data;
+ unsigned char mux_sel;
+ struct da9055 *da9055 = hwmon->da9055;
+
+ if (channel > DA9055_ADC_TJUNC)
+ return -EINVAL;
+
+ mutex_lock(&hwmon->irq_lock);
+
+ /* Selects desired MUX for manual conversion */
+ mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV;
+
+ ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel);
+ if (ret < 0)
+ goto err;
+
+ /* Wait for an interrupt */
+ if (!wait_for_completion_timeout(&hwmon->done,
+ msecs_to_jiffies(500))) {
+ dev_err(da9055->dev,
+ "timeout waiting for ADC conversion interrupt\n");
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H);
+ if (ret < 0)
+ goto err;
+
+ calc_data = (unsigned short)ret;
+ data = calc_data << 2;
+
+ ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L);
+ if (ret < 0)
+ goto err;
+
+ calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK);
+ data |= calc_data;
+
+ ret = data;
+
+err:
+ mutex_unlock(&hwmon->irq_lock);
+ return ret;
+}
+
+static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data)
+{
+ struct da9055_hwmon *hwmon = irq_data;
+
+ complete(&hwmon->done);
+
+ return IRQ_HANDLED;
+}
+
+/* Conversion function for VSYS and ADCINx */
+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;
+ else
+ return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV);
+}
+
+static int da9055_enable_auto_mode(struct da9055 *da9055, int channel)
+{
+
+ return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel,
+ 1 << channel);
+
+}
+
+static int da9055_disable_auto_mode(struct da9055 *da9055, int channel)
+{
+
+ return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0);
+}
+
+static ssize_t da9055_read_auto_ch(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
+ int ret, adc;
+ int channel = to_sensor_dev_attr(devattr)->index;
+
+ mutex_lock(&hwmon->hwmon_lock);
+
+ ret = da9055_enable_auto_mode(hwmon->da9055, channel);
+ if (ret < 0)
+ goto hwmon_err;
+
+ usleep_range(10000, 10500);
+
+ adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel);
+ if (adc < 0) {
+ ret = adc;
+ goto hwmon_err_release;
+ }
+
+ ret = da9055_disable_auto_mode(hwmon->da9055, channel);
+ if (ret < 0)
+ goto hwmon_err;
+
+ mutex_unlock(&hwmon->hwmon_lock);
+
+ return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel));
+
+hwmon_err_release:
+ da9055_disable_auto_mode(hwmon->da9055, channel);
+hwmon_err:
+ mutex_unlock(&hwmon->hwmon_lock);
+ return ret;
+}
+
+static ssize_t da9055_read_tjunc(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct da9055_hwmon *hwmon = dev_get_drvdata(dev);
+ int tjunc;
+ int toffset;
+
+ tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC);
+ if (tjunc < 0)
+ return tjunc;
+
+ toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET);
+ if (toffset < 0)
+ return toffset;
+
+ /*
+ * Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332
+ * T_OFFSET is a trim value used to improve accuracy of the result
+ */
+ return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset)
+ + 3076332, 10000));
+}
+
+static ssize_t da9055_hwmon_show_name(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ return sprintf(buf, "da9055-hwmon\n");
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "%s\n",
+ input_names[to_sensor_dev_attr(devattr)->index]);
+}
+
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_VSYS);
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_VSYS);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_ADCIN1);
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_ADCIN1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_ADCIN2);
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_ADCIN2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL,
+ DA9055_ADC_ADCIN3);
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_ADCIN3);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL,
+ DA9055_ADC_TJUNC);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL,
+ DA9055_ADC_TJUNC);
+
+static DEVICE_ATTR(name, S_IRUGO, da9055_hwmon_show_name, NULL);
+
+static struct attribute *da9055_attr[] = {
+ &dev_attr_name.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_label.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_label.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_label.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_label.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group da9055_attr_group = {.attrs = da9055_attr};
+
+static int da9055_hwmon_probe(struct platform_device *pdev)
+{
+ struct da9055_hwmon *hwmon;
+ int hwmon_irq, ret;
+
+ hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9055_hwmon),
+ GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ mutex_init(&hwmon->hwmon_lock);
+ mutex_init(&hwmon->irq_lock);
+
+ init_completion(&hwmon->done);
+ hwmon->da9055 = dev_get_drvdata(pdev->dev.parent);
+
+ platform_set_drvdata(pdev, hwmon);
+
+ hwmon_irq = platform_get_irq_byname(pdev, "HWMON");
+ if (hwmon_irq < 0)
+ return hwmon_irq;
+
+ hwmon_irq = regmap_irq_get_virq(hwmon->da9055->irq_data, hwmon_irq);
+ if (hwmon_irq < 0)
+ return hwmon_irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq,
+ NULL, da9055_auxadc_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "adc-irq", hwmon);
+ if (ret != 0) {
+ dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &da9055_attr_group);
+ if (ret)
+ return ret;
+
+ hwmon->class_device = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon->class_device)) {
+ ret = PTR_ERR(hwmon->class_device);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
+ return ret;
+}
+
+static int da9055_hwmon_remove(struct platform_device *pdev)
+{
+ struct da9055_hwmon *hwmon = platform_get_drvdata(pdev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group);
+ hwmon_device_unregister(hwmon->class_device);
+
+ return 0;
+}
+
+static struct platform_driver da9055_hwmon_driver = {
+ .probe = da9055_hwmon_probe,
+ .remove = da9055_hwmon_remove,
+ .driver = {
+ .name = "da9055-hwmon",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(da9055_hwmon_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 HWMON driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-hwmon");
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 4f4110407387..34ab2a8f9654 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -31,6 +31,9 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>");
MODULE_LICENSE("GPL");
+/* Family 16h Northbridge's function 4 PCI ID */
+#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534
+
/* D18F3 */
#define REG_NORTHBRIDGE_CAP 0xe8
@@ -248,6 +251,7 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev)
static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{}
};
MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 2b726346f8fa..8e7158c3ad2f 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -302,19 +302,8 @@ static struct i2c_driver ina2xx_driver = {
.id_table = ina2xx_id,
};
-static int __init ina2xx_init(void)
-{
- return i2c_add_driver(&ina2xx_driver);
-}
-
-static void __exit ina2xx_exit(void)
-{
- i2c_del_driver(&ina2xx_driver);
-}
+module_i2c_driver(ina2xx_driver);
MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
MODULE_DESCRIPTION("ina2xx driver");
MODULE_LICENSE("GPL");
-
-module_init(ina2xx_init);
-module_exit(ina2xx_exit);
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index aa59a254be2c..c02bf208084f 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -39,6 +39,7 @@
#define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */
#define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */
#define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */
+#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */
#define AT91_TWI_SWRST 0x0080 /* Software Reset */
#define AT91_TWI_MMR 0x0004 /* Master Mode Register */
@@ -212,7 +213,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
INIT_COMPLETION(dev->cmd_complete);
dev->transfer_status = 0;
- if (dev->msg->flags & I2C_M_RD) {
+
+ if (!dev->buf_len) {
+ at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK);
+ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP);
+ } else if (dev->msg->flags & I2C_M_RD) {
unsigned start_flags = AT91_TWI_START;
if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) {
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 286ca1917820..0670da79ee5e 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -287,12 +287,14 @@ read_init_dma_fail:
select_init_dma_fail:
dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE);
select_init_pio_fail:
+ dmaengine_terminate_all(i2c->dmach);
return -EINVAL;
/* Write failpath. */
write_init_dma_fail:
dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE);
write_init_pio_fail:
+ dmaengine_terminate_all(i2c->dmach);
return -EINVAL;
}
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index db31eaed6ea5..3525c9e62cb0 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -43,7 +43,6 @@
#include <linux/slab.h>
#include <linux/i2c-omap.h>
#include <linux/pm_runtime.h>
-#include <linux/pm_qos.h>
/* I2C controller revisions */
#define OMAP_I2C_OMAP1_REV_2 0x20
@@ -187,8 +186,9 @@ struct omap_i2c_dev {
int reg_shift; /* bit shift for I2C register addresses */
struct completion cmd_complete;
struct resource *ioarea;
- u32 latency; /* maximum MPU wkup latency */
- struct pm_qos_request pm_qos_request;
+ u32 latency; /* maximum mpu wkup latency */
+ void (*set_mpu_wkup_lat)(struct device *dev,
+ long latency);
u32 speed; /* Speed of bus in kHz */
u32 dtrev; /* extra revision from DT */
u32 flags;
@@ -494,7 +494,9 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx)
dev->b_hw = 1; /* Enable hardware fixes */
/* calculate wakeup latency constraint for MPU */
- dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8);
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->latency = (1000000 * dev->threshold) /
+ (1000 * dev->speed / 8);
}
/*
@@ -522,6 +524,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
dev->buf = msg->buf;
dev->buf_len = msg->len;
+ /* make sure writes to dev->buf_len are ordered */
+ barrier();
+
omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
/* Clear the FIFO Buffers */
@@ -579,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
*/
timeout = wait_for_completion_timeout(&dev->cmd_complete,
OMAP_I2C_TIMEOUT);
- dev->buf_len = 0;
if (timeout == 0) {
dev_err(dev->dev, "controller timed out\n");
omap_i2c_init(dev);
@@ -629,16 +633,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
if (r < 0)
goto out;
- /*
- * When waiting for completion of a i2c transfer, we need to
- * set a wake up latency constraint for the MPU. This is to
- * ensure quick enough wakeup from idle, when transfer
- * completes.
- */
- if (dev->latency)
- pm_qos_add_request(&dev->pm_qos_request,
- PM_QOS_CPU_DMA_LATENCY,
- dev->latency);
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, dev->latency);
for (i = 0; i < num; i++) {
r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
@@ -646,8 +642,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
break;
}
- if (dev->latency)
- pm_qos_remove_request(&dev->pm_qos_request);
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->set_mpu_wkup_lat(dev->dev, -1);
if (r == 0)
r = num;
@@ -1104,6 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev)
} else if (pdata != NULL) {
dev->speed = pdata->clkrate;
dev->flags = pdata->flags;
+ dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;
dev->dtrev = pdata->rev;
}
@@ -1159,8 +1156,9 @@ omap_i2c_probe(struct platform_device *pdev)
dev->b_hw = 1; /* Enable hardware fixes */
/* calculate wakeup latency constraint for MPU */
- dev->latency = (1000000 * dev->fifo_size) /
- (1000 * dev->speed / 8);
+ if (dev->set_mpu_wkup_lat != NULL)
+ dev->latency = (1000000 * dev->fifo_size) /
+ (1000 * dev->speed / 8);
}
/* reset ASAP, clearing any IRQs */
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 3e0335f1fc60..9d902725bac9 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -806,6 +806,7 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c)
dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio);
goto free_gpio;
}
+ i2c->gpios[idx] = gpio;
ret = gpio_request(gpio, "i2c-bus");
if (ret) {
diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c
index 5f097f309b9f..7fa5b24b16db 100644
--- a/drivers/i2c/muxes/i2c-mux-pinctrl.c
+++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c
@@ -169,7 +169,7 @@ static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev)
mux->busses = devm_kzalloc(&pdev->dev,
sizeof(mux->busses) * mux->pdata->bus_count,
GFP_KERNEL);
- if (!mux->states) {
+ if (!mux->busses) {
dev_err(&pdev->dev, "Cannot allocate busses\n");
ret = -ENOMEM;
goto err;
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index c0ec7d42c3be..1abbc170d8b7 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -26,10 +26,14 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
* input_mt_init_slots() - initialize MT input slots
* @dev: input device supporting MT events and finger tracking
* @num_slots: number of slots used by the device
+ * @flags: mt tasks to handle in core
*
* This function allocates all necessary memory for MT slot handling
* in the input device, prepares the ABS_MT_SLOT and
* ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
+ * Depending on the flags set, it also performs pointer emulation and
+ * frame synchronization.
+ *
* May be called repeatedly. Returns -EINVAL if attempting to
* reinitialize with a different number of slots.
*/
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c
index 443ad64b7f2a..d88d9be1d1b7 100644
--- a/drivers/input/matrix-keymap.c
+++ b/drivers/input/matrix-keymap.c
@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/of.h>
#include <linux/export.h>
+#include <linux/module.h>
#include <linux/input/matrix_keypad.h>
static bool matrix_keypad_map_key(struct input_dev *input_dev,
@@ -161,3 +162,5 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
return 0;
}
EXPORT_SYMBOL(matrix_keypad_build_keymap);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 8f02e3d0e712..4c842c320c2e 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -12,8 +12,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define MOUSEDEV_MINOR_BASE 32
-#define MOUSEDEV_MINORS 32
-#define MOUSEDEV_MIX 31
+#define MOUSEDEV_MINORS 31
+#define MOUSEDEV_MIX 63
#include <linux/sched.h>
#include <linux/slab.h>
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index f02028ec3db6..78e5d9ab0ba7 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -955,7 +955,8 @@ static int ads7846_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume);
-static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts)
+static int __devinit ads7846_setup_pendown(struct spi_device *spi,
+ struct ads7846 *ts)
{
struct ads7846_platform_data *pdata = spi->dev.platform_data;
int err;
@@ -981,6 +982,9 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
ts->gpio_pendown = pdata->gpio_pendown;
+ if (pdata->gpio_pendown_debounce)
+ gpio_set_debounce(pdata->gpio_pendown,
+ pdata->gpio_pendown_debounce);
} else {
dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
return -EINVAL;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index d4a4cd445cab..0badfa48b32b 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4108,7 +4108,7 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to)
static int intel_iommu_add_device(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct pci_dev *bridge, *dma_pdev;
+ struct pci_dev *bridge, *dma_pdev = NULL;
struct iommu_group *group;
int ret;
@@ -4122,7 +4122,7 @@ static int intel_iommu_add_device(struct device *dev)
dma_pdev = pci_get_domain_bus_and_slot(
pci_domain_nr(pdev->bus),
bridge->subordinate->number, 0);
- else
+ if (!dma_pdev)
dma_pdev = pci_dev_get(bridge);
} else
dma_pdev = pci_dev_get(pdev);
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index a649f146d17b..c0f7a4266263 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -1054,6 +1054,7 @@ static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
stats[i], val, offs);
}
seq_printf(s, "\n");
+ dput(dent);
return 0;
}
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c
index dc670ccc6978..16c78f1c5ef2 100644
--- a/drivers/irqchip/irq-bcm2835.c
+++ b/drivers/irqchip/irq-bcm2835.c
@@ -168,7 +168,8 @@ static int __init armctrl_of_init(struct device_node *node,
}
static struct of_device_id irq_of_match[] __initconst = {
- { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init }
+ { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init },
+ { }
};
void __init bcm2835_init_irq(void)
diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c
index b312056da14d..4239b3955ff0 100644
--- a/drivers/leds/ledtrig-cpu.c
+++ b/drivers/leds/ledtrig-cpu.c
@@ -33,8 +33,6 @@
struct led_trigger_cpu {
char name[MAX_NAME_LEN];
struct led_trigger *_trig;
- struct mutex lock;
- int lock_is_inited;
};
static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
@@ -50,12 +48,6 @@ void ledtrig_cpu(enum cpu_led_event ledevt)
{
struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig);
- /* mutex lock should be initialized before calling mutex_call() */
- if (!trig->lock_is_inited)
- return;
-
- mutex_lock(&trig->lock);
-
/* Locate the correct CPU LED */
switch (ledevt) {
case CPU_LED_IDLE_END:
@@ -75,8 +67,6 @@ void ledtrig_cpu(enum cpu_led_event ledevt)
/* Will leave the LED as it is */
break;
}
-
- mutex_unlock(&trig->lock);
}
EXPORT_SYMBOL(ledtrig_cpu);
@@ -117,14 +107,9 @@ static int __init ledtrig_cpu_init(void)
for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
- mutex_init(&trig->lock);
-
snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
- mutex_lock(&trig->lock);
led_trigger_register_simple(trig->name, &trig->_trig);
- trig->lock_is_inited = 1;
- mutex_unlock(&trig->lock);
}
register_syscore_ops(&ledtrig_cpu_syscore_ops);
@@ -142,15 +127,9 @@ static void __exit ledtrig_cpu_exit(void)
for_each_possible_cpu(cpu) {
struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
- mutex_lock(&trig->lock);
-
led_trigger_unregister_simple(trig->_trig);
trig->_trig = NULL;
memset(trig->name, 0, MAX_NAME_LEN);
- trig->lock_is_inited = 0;
-
- mutex_unlock(&trig->lock);
- mutex_destroy(&trig->lock);
}
unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 02db9183ca01..77e6eff41cae 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -740,8 +740,14 @@ static void rq_completed(struct mapped_device *md, int rw, int run_queue)
if (!md_in_flight(md))
wake_up(&md->wait);
+ /*
+ * Run this off this callpath, as drivers could invoke end_io while
+ * inside their request_fn (and holding the queue lock). Calling
+ * back into ->request_fn() could deadlock attempting to grab the
+ * queue lock again.
+ */
if (run_queue)
- blk_run_queue(md->queue);
+ blk_run_queue_async(md->queue);
/*
* dm_put() must be at the end of this function. See the comment above
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 9ab768acfb62..61200717687b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1817,10 +1817,10 @@ retry:
memset(bbp, 0xff, PAGE_SIZE);
for (i = 0 ; i < bb->count ; i++) {
- u64 internal_bb = *p++;
+ u64 internal_bb = p[i];
u64 store_bb = ((BB_OFFSET(internal_bb) << 10)
| BB_LEN(internal_bb));
- *bbp++ = cpu_to_le64(store_bb);
+ bbp[i] = cpu_to_le64(store_bb);
}
bb->changed = 0;
if (read_seqretry(&bb->lock, seq))
@@ -5294,7 +5294,7 @@ void md_stop_writes(struct mddev *mddev)
}
EXPORT_SYMBOL_GPL(md_stop_writes);
-void md_stop(struct mddev *mddev)
+static void __md_stop(struct mddev *mddev)
{
mddev->ready = 0;
mddev->pers->stop(mddev);
@@ -5304,6 +5304,18 @@ void md_stop(struct mddev *mddev)
mddev->pers = NULL;
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
}
+
+void md_stop(struct mddev *mddev)
+{
+ /* stop the array and free an attached data structures.
+ * This is called from dm-raid
+ */
+ __md_stop(mddev);
+ bitmap_destroy(mddev);
+ if (mddev->bio_set)
+ bioset_free(mddev->bio_set);
+}
+
EXPORT_SYMBOL_GPL(md_stop);
static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
@@ -5364,7 +5376,7 @@ static int do_md_stop(struct mddev * mddev, int mode,
set_disk_ro(disk, 0);
__md_stop_writes(mddev);
- md_stop(mddev);
+ __md_stop(mddev);
mddev->queue->merge_bvec_fn = NULL;
mddev->queue->backing_dev_info.congested_fn = NULL;
@@ -7936,9 +7948,9 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
sector_t *first_bad, int *bad_sectors)
{
int hi;
- int lo = 0;
+ int lo;
u64 *p = bb->page;
- int rv = 0;
+ int rv;
sector_t target = s + sectors;
unsigned seq;
@@ -7953,7 +7965,8 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors,
retry:
seq = read_seqbegin(&bb->lock);
-
+ lo = 0;
+ rv = 0;
hi = bb->count;
/* Binary search between lo and hi for 'target'
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 636bae0405e8..a0f73092176e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -963,7 +963,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule)
struct r1conf *conf = mddev->private;
struct bio *bio;
- if (from_schedule) {
+ if (from_schedule || current->bio_list) {
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
conf->pending_count += plug->pending_cnt;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index d1295aff4173..c9acbd717131 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -499,7 +499,7 @@ static void raid10_end_write_request(struct bio *bio, int error)
*/
one_write_done(r10_bio);
if (dec_rdev)
- rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
+ rdev_dec_pending(rdev, conf->mddev);
}
/*
@@ -1069,7 +1069,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
struct r10conf *conf = mddev->private;
struct bio *bio;
- if (from_schedule) {
+ if (from_schedule || current->bio_list) {
spin_lock_irq(&conf->device_lock);
bio_list_merge(&conf->pending_bio_list, &plug->pending);
conf->pending_count += plug->pending_cnt;
@@ -1334,18 +1334,21 @@ retry_write:
blocked_rdev = rrdev;
break;
}
+ if (rdev && (test_bit(Faulty, &rdev->flags)
+ || test_bit(Unmerged, &rdev->flags)))
+ rdev = NULL;
if (rrdev && (test_bit(Faulty, &rrdev->flags)
|| test_bit(Unmerged, &rrdev->flags)))
rrdev = NULL;
r10_bio->devs[i].bio = NULL;
r10_bio->devs[i].repl_bio = NULL;
- if (!rdev || test_bit(Faulty, &rdev->flags) ||
- test_bit(Unmerged, &rdev->flags)) {
+
+ if (!rdev && !rrdev) {
set_bit(R10BIO_Degraded, &r10_bio->state);
continue;
}
- if (test_bit(WriteErrorSeen, &rdev->flags)) {
+ if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) {
sector_t first_bad;
sector_t dev_sector = r10_bio->devs[i].addr;
int bad_sectors;
@@ -1387,8 +1390,10 @@ retry_write:
max_sectors = good_sectors;
}
}
- r10_bio->devs[i].bio = bio;
- atomic_inc(&rdev->nr_pending);
+ if (rdev) {
+ r10_bio->devs[i].bio = bio;
+ atomic_inc(&rdev->nr_pending);
+ }
if (rrdev) {
r10_bio->devs[i].repl_bio = bio;
atomic_inc(&rrdev->nr_pending);
@@ -1444,69 +1449,71 @@ retry_write:
for (i = 0; i < conf->copies; i++) {
struct bio *mbio;
int d = r10_bio->devs[i].devnum;
- if (!r10_bio->devs[i].bio)
- continue;
+ if (r10_bio->devs[i].bio) {
+ struct md_rdev *rdev = conf->mirrors[d].rdev;
+ mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+ md_trim_bio(mbio, r10_bio->sector - bio->bi_sector,
+ max_sectors);
+ r10_bio->devs[i].bio = mbio;
+
+ mbio->bi_sector = (r10_bio->devs[i].addr+
+ choose_data_offset(r10_bio,
+ rdev));
+ mbio->bi_bdev = rdev->bdev;
+ mbio->bi_end_io = raid10_end_write_request;
+ mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
+ mbio->bi_private = r10_bio;
- mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
- md_trim_bio(mbio, r10_bio->sector - bio->bi_sector,
- max_sectors);
- r10_bio->devs[i].bio = mbio;
+ atomic_inc(&r10_bio->remaining);
- mbio->bi_sector = (r10_bio->devs[i].addr+
- choose_data_offset(r10_bio,
- conf->mirrors[d].rdev));
- mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
- mbio->bi_end_io = raid10_end_write_request;
- mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
- mbio->bi_private = r10_bio;
+ cb = blk_check_plugged(raid10_unplug, mddev,
+ sizeof(*plug));
+ if (cb)
+ plug = container_of(cb, struct raid10_plug_cb,
+ cb);
+ else
+ plug = NULL;
+ spin_lock_irqsave(&conf->device_lock, flags);
+ if (plug) {
+ bio_list_add(&plug->pending, mbio);
+ plug->pending_cnt++;
+ } else {
+ bio_list_add(&conf->pending_bio_list, mbio);
+ conf->pending_count++;
+ }
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (!plug)
+ md_wakeup_thread(mddev->thread);
+ }
- atomic_inc(&r10_bio->remaining);
+ if (r10_bio->devs[i].repl_bio) {
+ struct md_rdev *rdev = conf->mirrors[d].replacement;
+ if (rdev == NULL) {
+ /* Replacement just got moved to main 'rdev' */
+ smp_mb();
+ rdev = conf->mirrors[d].rdev;
+ }
+ mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+ md_trim_bio(mbio, r10_bio->sector - bio->bi_sector,
+ max_sectors);
+ r10_bio->devs[i].repl_bio = mbio;
+
+ mbio->bi_sector = (r10_bio->devs[i].addr +
+ choose_data_offset(
+ r10_bio, rdev));
+ mbio->bi_bdev = rdev->bdev;
+ mbio->bi_end_io = raid10_end_write_request;
+ mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
+ mbio->bi_private = r10_bio;
- cb = blk_check_plugged(raid10_unplug, mddev, sizeof(*plug));
- if (cb)
- plug = container_of(cb, struct raid10_plug_cb, cb);
- else
- plug = NULL;
- spin_lock_irqsave(&conf->device_lock, flags);
- if (plug) {
- bio_list_add(&plug->pending, mbio);
- plug->pending_cnt++;
- } else {
+ atomic_inc(&r10_bio->remaining);
+ spin_lock_irqsave(&conf->device_lock, flags);
bio_list_add(&conf->pending_bio_list, mbio);
conf->pending_count++;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ if (!mddev_check_plugged(mddev))
+ md_wakeup_thread(mddev->thread);
}
- spin_unlock_irqrestore(&conf->device_lock, flags);
- if (!plug)
- md_wakeup_thread(mddev->thread);
-
- if (!r10_bio->devs[i].repl_bio)
- continue;
-
- mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
- md_trim_bio(mbio, r10_bio->sector - bio->bi_sector,
- max_sectors);
- r10_bio->devs[i].repl_bio = mbio;
-
- /* We are actively writing to the original device
- * so it cannot disappear, so the replacement cannot
- * become NULL here
- */
- mbio->bi_sector = (r10_bio->devs[i].addr +
- choose_data_offset(
- r10_bio,
- conf->mirrors[d].replacement));
- mbio->bi_bdev = conf->mirrors[d].replacement->bdev;
- mbio->bi_end_io = raid10_end_write_request;
- mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
- mbio->bi_private = r10_bio;
-
- atomic_inc(&r10_bio->remaining);
- spin_lock_irqsave(&conf->device_lock, flags);
- bio_list_add(&conf->pending_bio_list, mbio);
- conf->pending_count++;
- spin_unlock_irqrestore(&conf->device_lock, flags);
- if (!mddev_check_plugged(mddev))
- md_wakeup_thread(mddev->thread);
}
/* Don't remove the bias on 'remaining' (one_write_done) until
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c5439dce0295..a4502686e7a8 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2774,10 +2774,12 @@ static void handle_stripe_clean_event(struct r5conf *conf,
dev = &sh->dev[i];
if (!test_bit(R5_LOCKED, &dev->flags) &&
(test_bit(R5_UPTODATE, &dev->flags) ||
- test_and_clear_bit(R5_Discard, &dev->flags))) {
+ test_bit(R5_Discard, &dev->flags))) {
/* We can return any write requests */
struct bio *wbi, *wbi2;
pr_debug("Return write for disc %d\n", i);
+ if (test_and_clear_bit(R5_Discard, &dev->flags))
+ clear_bit(R5_UPTODATE, &dev->flags);
wbi = dev->written;
dev->written = NULL;
while (wbi && wbi->bi_sector <
@@ -2795,7 +2797,8 @@ static void handle_stripe_clean_event(struct r5conf *conf,
!test_bit(STRIPE_DEGRADED, &sh->state),
0);
}
- }
+ } else if (test_bit(R5_Discard, &sh->dev[i].flags))
+ clear_bit(R5_Discard, &sh->dev[i].flags);
if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state))
if (atomic_dec_and_test(&conf->pending_full_writes))
@@ -3490,40 +3493,6 @@ static void handle_stripe(struct stripe_head *sh)
handle_failed_sync(conf, sh, &s);
}
- /*
- * might be able to return some write requests if the parity blocks
- * are safe, or on a failed drive
- */
- pdev = &sh->dev[sh->pd_idx];
- s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx)
- || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx);
- qdev = &sh->dev[sh->qd_idx];
- s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx)
- || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx)
- || conf->level < 6;
-
- if (s.written &&
- (s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
- && !test_bit(R5_LOCKED, &pdev->flags)
- && (test_bit(R5_UPTODATE, &pdev->flags) ||
- test_bit(R5_Discard, &pdev->flags))))) &&
- (s.q_failed || ((test_bit(R5_Insync, &qdev->flags)
- && !test_bit(R5_LOCKED, &qdev->flags)
- && (test_bit(R5_UPTODATE, &qdev->flags) ||
- test_bit(R5_Discard, &qdev->flags))))))
- handle_stripe_clean_event(conf, sh, disks, &s.return_bi);
-
- /* Now we might consider reading some blocks, either to check/generate
- * parity, or to satisfy requests
- * or to load a block that is being partially written.
- */
- if (s.to_read || s.non_overwrite
- || (conf->level == 6 && s.to_write && s.failed)
- || (s.syncing && (s.uptodate + s.compute < disks))
- || s.replacing
- || s.expanding)
- handle_stripe_fill(sh, &s, disks);
-
/* Now we check to see if any write operations have recently
* completed
*/
@@ -3561,6 +3530,40 @@ static void handle_stripe(struct stripe_head *sh)
s.dec_preread_active = 1;
}
+ /*
+ * might be able to return some write requests if the parity blocks
+ * are safe, or on a failed drive
+ */
+ pdev = &sh->dev[sh->pd_idx];
+ s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx)
+ || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx);
+ qdev = &sh->dev[sh->qd_idx];
+ s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx)
+ || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx)
+ || conf->level < 6;
+
+ if (s.written &&
+ (s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
+ && !test_bit(R5_LOCKED, &pdev->flags)
+ && (test_bit(R5_UPTODATE, &pdev->flags) ||
+ test_bit(R5_Discard, &pdev->flags))))) &&
+ (s.q_failed || ((test_bit(R5_Insync, &qdev->flags)
+ && !test_bit(R5_LOCKED, &qdev->flags)
+ && (test_bit(R5_UPTODATE, &qdev->flags) ||
+ test_bit(R5_Discard, &qdev->flags))))))
+ handle_stripe_clean_event(conf, sh, disks, &s.return_bi);
+
+ /* Now we might consider reading some blocks, either to check/generate
+ * parity, or to satisfy requests
+ * or to load a block that is being partially written.
+ */
+ if (s.to_read || s.non_overwrite
+ || (conf->level == 6 && s.to_write && s.failed)
+ || (s.syncing && (s.uptodate + s.compute < disks))
+ || s.replacing
+ || s.expanding)
+ handle_stripe_fill(sh, &s, disks);
+
/* Now to consider new write requests and what else, if anything
* should be read. We do not handle new writes when:
* 1/ A 'write' operation (copy+xor) is already in flight.
@@ -5529,6 +5532,10 @@ static int run(struct mddev *mddev)
* discard data disk but write parity disk
*/
stripe = stripe * PAGE_SIZE;
+ /* Round up to power of 2, as discard handling
+ * currently assumes that */
+ while ((stripe-1) & stripe)
+ stripe = (stripe | (stripe-1)) + 1;
mddev->queue->limits.discard_alignment = stripe;
mddev->queue->limits.discard_granularity = stripe;
/*
diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c
index 262dfa503c2a..b551ca350e00 100644
--- a/drivers/media/dvb-frontends/stv0900_core.c
+++ b/drivers/media/dvb-frontends/stv0900_core.c
@@ -300,15 +300,15 @@ static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32
{
u32 m_div, clk_sel;
- dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
- intp->quartz);
-
if (intp == NULL)
return STV0900_INVALID_HANDLE;
if (intp->errs)
return STV0900_I2C_ERROR;
+ dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk,
+ intp->quartz);
+
clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6);
m_div = ((clk_sel * mclk) / intp->quartz) - 1;
stv0900_write_bits(intp, F0900_M_DIV, m_div);
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 109bc9b12e74..05f8950f6f91 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -53,8 +53,7 @@ MODULE_LICENSE("GPL");
/* ADV7604 system clock frequency */
#define ADV7604_fsc (28636360)
-#define DIGITAL_INPUT ((state->prim_mode == ADV7604_PRIM_MODE_HDMI_COMP) || \
- (state->prim_mode == ADV7604_PRIM_MODE_HDMI_GR))
+#define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI)
/*
**********************************************************************
@@ -68,7 +67,7 @@ struct adv7604_state {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_ctrl_handler hdl;
- enum adv7604_prim_mode prim_mode;
+ enum adv7604_mode mode;
struct v4l2_dv_timings timings;
u8 edid[256];
unsigned edid_blocks;
@@ -77,6 +76,7 @@ struct adv7604_state {
struct workqueue_struct *work_queues;
struct delayed_work delayed_work_enable_hotplug;
bool connector_hdmi;
+ bool restart_stdi_once;
/* i2c clients */
struct i2c_client *i2c_avlink;
@@ -106,7 +106,6 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
V4L2_DV_BT_CEA_720X576P50,
V4L2_DV_BT_CEA_1280X720P24,
V4L2_DV_BT_CEA_1280X720P25,
- V4L2_DV_BT_CEA_1280X720P30,
V4L2_DV_BT_CEA_1280X720P50,
V4L2_DV_BT_CEA_1280X720P60,
V4L2_DV_BT_CEA_1920X1080P24,
@@ -115,6 +114,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
V4L2_DV_BT_CEA_1920X1080P50,
V4L2_DV_BT_CEA_1920X1080P60,
+ /* sorted by DMT ID */
V4L2_DV_BT_DMT_640X350P85,
V4L2_DV_BT_DMT_640X400P85,
V4L2_DV_BT_DMT_720X400P85,
@@ -164,6 +164,89 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
{ },
};
+struct adv7604_video_standards {
+ struct v4l2_dv_timings timings;
+ u8 vid_std;
+ u8 v_freq;
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_comp[] = {
+ /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */
+ { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
+ { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 },
+ { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 },
+ { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 },
+ { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 },
+ { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 },
+ { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 },
+ { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 },
+ /* TODO add 1920x1080P60_RB (CVT timing) */
+ { },
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_gr[] = {
+ { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 },
+ { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 },
+ { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 },
+ { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 },
+ { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 },
+ { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */
+ /* TODO add 1600X1200P60_RB (not a DMT timing) */
+ { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 },
+ { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */
+ { },
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = {
+ { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 },
+ { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 },
+ { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 },
+ { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 },
+ { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 },
+ { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 },
+ { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 },
+ { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 },
+ { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 },
+ { },
+};
+
+/* sorted by number of lines */
+static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = {
+ { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 },
+ { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 },
+ { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 },
+ { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 },
+ { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 },
+ { },
+};
+
/* ----------------------------------------------------------------------- */
static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
@@ -672,64 +755,144 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
((io_read(sd, 0x6f) & 0x10) >> 4));
}
-static void configure_free_run(struct v4l2_subdev *sd, const struct v4l2_bt_timings *timings)
+static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
+ u8 prim_mode,
+ const struct adv7604_video_standards *predef_vid_timings,
+ const struct v4l2_dv_timings *timings)
+{
+ struct adv7604_state *state = to_state(sd);
+ int i;
+
+ for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
+ if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings,
+ DIGITAL_INPUT ? 250000 : 1000000))
+ continue;
+ io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
+ io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) +
+ prim_mode); /* v_freq and prim mode */
+ return 0;
+ }
+
+ return -1;
+}
+
+static int configure_predefined_video_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
{
+ struct adv7604_state *state = to_state(sd);
+ int err;
+
+ v4l2_dbg(1, debug, sd, "%s", __func__);
+
+ /* reset to default values */
+ io_write(sd, 0x16, 0x43);
+ io_write(sd, 0x17, 0x5a);
+ /* disable embedded syncs for auto graphics mode */
+ cp_write_and_or(sd, 0x81, 0xef, 0x00);
+ cp_write(sd, 0x8f, 0x00);
+ cp_write(sd, 0x90, 0x00);
+ cp_write(sd, 0xa2, 0x00);
+ cp_write(sd, 0xa3, 0x00);
+ cp_write(sd, 0xa4, 0x00);
+ cp_write(sd, 0xa5, 0x00);
+ cp_write(sd, 0xa6, 0x00);
+ cp_write(sd, 0xa7, 0x00);
+ cp_write(sd, 0xab, 0x00);
+ cp_write(sd, 0xac, 0x00);
+
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
+ err = find_and_set_predefined_video_timings(sd,
+ 0x01, adv7604_prim_mode_comp, timings);
+ if (err)
+ err = find_and_set_predefined_video_timings(sd,
+ 0x02, adv7604_prim_mode_gr, timings);
+ break;
+ case ADV7604_MODE_HDMI:
+ err = find_and_set_predefined_video_timings(sd,
+ 0x05, adv7604_prim_mode_hdmi_comp, timings);
+ if (err)
+ err = find_and_set_predefined_video_timings(sd,
+ 0x06, adv7604_prim_mode_hdmi_gr, timings);
+ break;
+ default:
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
+ err = -1;
+ break;
+ }
+
+
+ return err;
+}
+
+static void configure_custom_video_timings(struct v4l2_subdev *sd,
+ const struct v4l2_bt_timings *bt)
+{
+ struct adv7604_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- u32 width = htotal(timings);
- u32 height = vtotal(timings);
- u16 ch1_fr_ll = (((u32)timings->pixelclock / 100) > 0) ?
- ((width * (ADV7604_fsc / 100)) / ((u32)timings->pixelclock / 100)) : 0;
+ u32 width = htotal(bt);
+ u32 height = vtotal(bt);
+ u16 cp_start_sav = bt->hsync + bt->hbackporch - 4;
+ u16 cp_start_eav = width - bt->hfrontporch;
+ u16 cp_start_vbi = height - bt->vfrontporch;
+ u16 cp_end_vbi = bt->vsync + bt->vbackporch;
+ u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ?
+ ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0;
+ const u8 pll[2] = {
+ 0xc0 | ((width >> 8) & 0x1f),
+ width & 0xff
+ };
v4l2_dbg(2, debug, sd, "%s\n", __func__);
- cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); /* CH1_FR_LL */
- cp_write(sd, 0x90, ch1_fr_ll & 0xff); /* CH1_FR_LL */
- cp_write(sd, 0xab, (height >> 4) & 0xff); /* CP_LCOUNT_MAX */
- cp_write(sd, 0xac, (height & 0x0f) << 4); /* CP_LCOUNT_MAX */
- /* TODO support interlaced */
- cp_write(sd, 0x91, 0x10); /* INTERLACED */
-
- /* Should only be set in auto-graphics mode [REF_02 p. 91-92] */
- if ((io_read(sd, 0x00) == 0x07) && (io_read(sd, 0x01) == 0x02)) {
- u16 cp_start_sav, cp_start_eav, cp_start_vbi, cp_end_vbi;
- const u8 pll[2] = {
- (0xc0 | ((width >> 8) & 0x1f)),
- (width & 0xff)
- };
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
+ /* auto graphics */
+ io_write(sd, 0x00, 0x07); /* video std */
+ io_write(sd, 0x01, 0x02); /* prim mode */
+ /* enable embedded syncs for auto graphics mode */
+ cp_write_and_or(sd, 0x81, 0xef, 0x10);
+ /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */
/* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */
/* IO-map reg. 0x16 and 0x17 should be written in sequence */
if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) {
v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
- return;
+ break;
}
/* active video - horizontal timing */
- cp_start_sav = timings->hsync + timings->hbackporch - 4;
- cp_start_eav = width - timings->hfrontporch;
cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff);
- cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | ((cp_start_eav >> 8) & 0x0f));
+ cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) |
+ ((cp_start_eav >> 8) & 0x0f));
cp_write(sd, 0xa4, cp_start_eav & 0xff);
/* active video - vertical timing */
- cp_start_vbi = height - timings->vfrontporch;
- cp_end_vbi = timings->vsync + timings->vbackporch;
cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff);
- cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | ((cp_end_vbi >> 8) & 0xf));
+ cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) |
+ ((cp_end_vbi >> 8) & 0xf));
cp_write(sd, 0xa7, cp_end_vbi & 0xff);
- } else {
- /* reset to default values */
- io_write(sd, 0x16, 0x43);
- io_write(sd, 0x17, 0x5a);
- cp_write(sd, 0xa2, 0x00);
- cp_write(sd, 0xa3, 0x00);
- cp_write(sd, 0xa4, 0x00);
- cp_write(sd, 0xa5, 0x00);
- cp_write(sd, 0xa6, 0x00);
- cp_write(sd, 0xa7, 0x00);
+ break;
+ case ADV7604_MODE_HDMI:
+ /* set default prim_mode/vid_std for HDMI
+ accoring to [REF_03, c. 4.2] */
+ io_write(sd, 0x00, 0x02); /* video std */
+ io_write(sd, 0x01, 0x06); /* prim mode */
+ break;
+ default:
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
+ break;
}
-}
+ cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7);
+ cp_write(sd, 0x90, ch1_fr_ll & 0xff);
+ cp_write(sd, 0xab, (height >> 4) & 0xff);
+ cp_write(sd, 0xac, (height & 0x0f) << 4);
+}
static void set_rgb_quantization_range(struct v4l2_subdev *sd)
{
@@ -738,12 +901,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
switch (state->rgb_quantization_range) {
case V4L2_DV_RGB_RANGE_AUTO:
/* automatic */
- if ((hdmi_read(sd, 0x05) & 0x80) ||
- (state->prim_mode == ADV7604_PRIM_MODE_COMP) ||
- (state->prim_mode == ADV7604_PRIM_MODE_RGB)) {
- /* receiving HDMI or analog signal */
- io_write_and_or(sd, 0x02, 0x0f, 0xf0);
- } else {
+ if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) {
/* receiving DVI-D signal */
/* ADV7604 selects RGB limited range regardless of
@@ -756,6 +914,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
/* RGB full range (0-255) */
io_write_and_or(sd, 0x02, 0x0f, 0x10);
}
+ } else {
+ /* receiving HDMI or analog signal, set automode */
+ io_write_and_or(sd, 0x02, 0x0f, 0xf0);
}
break;
case V4L2_DV_RGB_RANGE_LIMITED:
@@ -967,8 +1128,10 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
state->aspect_ratio, timings))
return 0;
- v4l2_dbg(2, debug, sd, "%s: No format candidate found for lcf=%d, bl = %d\n",
- __func__, stdi->lcf, stdi->bl);
+ v4l2_dbg(2, debug, sd,
+ "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n",
+ __func__, stdi->lcvs, stdi->lcf, stdi->bl,
+ stdi->hs_pol, stdi->vs_pol);
return -1;
}
@@ -1123,7 +1286,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
adv7604_fill_optional_dv_timings_fields(sd, timings);
} else {
/* find format
- * Since LCVS values are inaccurate (REF_03, page 275-276),
+ * Since LCVS values are inaccurate [REF_03, p. 275-276],
* stdi2dv_timings() is called with lcvs +-1 if the first attempt fails.
*/
if (!stdi2dv_timings(sd, &stdi, timings))
@@ -1135,9 +1298,31 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
stdi.lcvs -= 2;
v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs);
if (stdi2dv_timings(sd, &stdi, timings)) {
+ /*
+ * The STDI block may measure wrong values, especially
+ * for lcvs and lcf. If the driver can not find any
+ * valid timing, the STDI block is restarted to measure
+ * the video timings again. The function will return an
+ * error, but the restart of STDI will generate a new
+ * STDI interrupt and the format detection process will
+ * restart.
+ */
+ if (state->restart_stdi_once) {
+ v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__);
+ /* TODO restart STDI for Sync Channel 2 */
+ /* enter one-shot mode */
+ cp_write_and_or(sd, 0x86, 0xf9, 0x00);
+ /* trigger STDI restart */
+ cp_write_and_or(sd, 0x86, 0xf9, 0x04);
+ /* reset to continuous mode */
+ cp_write_and_or(sd, 0x86, 0xf9, 0x02);
+ state->restart_stdi_once = false;
+ return -ENOLINK;
+ }
v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__);
return -ERANGE;
}
+ state->restart_stdi_once = true;
}
found:
@@ -1166,6 +1351,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
{
struct adv7604_state *state = to_state(sd);
struct v4l2_bt_timings *bt;
+ int err;
if (!timings)
return -EINVAL;
@@ -1178,12 +1364,20 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
__func__, (u32)bt->pixelclock);
return -ERANGE;
}
+
adv7604_fill_optional_dv_timings_fields(sd, timings);
state->timings = *timings;
- /* freerun */
- configure_free_run(sd, bt);
+ cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10);
+
+ /* Use prim_mode and vid_std when available */
+ err = configure_predefined_video_timings(sd, timings);
+ if (err) {
+ /* custom settings when the video format
+ does not have prim_mode/vid_std */
+ configure_custom_video_timings(sd, bt);
+ }
set_rgb_quantization_range(sd);
@@ -1203,24 +1397,25 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd,
return 0;
}
-static void enable_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode)
+static void enable_input(struct v4l2_subdev *sd)
{
- switch (prim_mode) {
- case ADV7604_PRIM_MODE_COMP:
- case ADV7604_PRIM_MODE_RGB:
+ struct adv7604_state *state = to_state(sd);
+
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
/* enable */
io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */
break;
- case ADV7604_PRIM_MODE_HDMI_COMP:
- case ADV7604_PRIM_MODE_HDMI_GR:
+ case ADV7604_MODE_HDMI:
/* enable */
hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */
hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */
io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */
break;
default:
- v4l2_err(sd, "%s: reserved primary mode 0x%0x\n",
- __func__, prim_mode);
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
break;
}
}
@@ -1233,17 +1428,13 @@ static void disable_input(struct v4l2_subdev *sd)
hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */
}
-static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode)
+static void select_input(struct v4l2_subdev *sd)
{
- switch (prim_mode) {
- case ADV7604_PRIM_MODE_COMP:
- case ADV7604_PRIM_MODE_RGB:
- /* set mode and select free run resolution */
- io_write(sd, 0x00, 0x07); /* video std */
- io_write(sd, 0x01, 0x02); /* prim mode */
- /* enable embedded syncs for auto graphics mode */
- cp_write_and_or(sd, 0x81, 0xef, 0x10);
+ struct adv7604_state *state = to_state(sd);
+ switch (state->mode) {
+ case ADV7604_MODE_COMP:
+ case ADV7604_MODE_GR:
/* reset ADI recommended settings for HDMI: */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */
@@ -1271,16 +1462,7 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod
cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */
break;
- case ADV7604_PRIM_MODE_HDMI_COMP:
- case ADV7604_PRIM_MODE_HDMI_GR:
- /* set mode and select free run resolution */
- /* video std */
- io_write(sd, 0x00,
- (prim_mode == ADV7604_PRIM_MODE_HDMI_GR) ? 0x02 : 0x1e);
- io_write(sd, 0x01, prim_mode); /* prim mode */
- /* disable embedded syncs for auto graphics mode */
- cp_write_and_or(sd, 0x81, 0xef, 0x00);
-
+ case ADV7604_MODE_HDMI:
/* set ADI recommended settings for HDMI: */
/* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */
@@ -1309,7 +1491,8 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod
break;
default:
- v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", __func__, prim_mode);
+ v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
+ __func__, state->mode);
break;
}
}
@@ -1321,26 +1504,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd,
v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input);
- switch (input) {
- case 0:
- /* TODO select HDMI_COMP or HDMI_GR */
- state->prim_mode = ADV7604_PRIM_MODE_HDMI_COMP;
- break;
- case 1:
- state->prim_mode = ADV7604_PRIM_MODE_RGB;
- break;
- case 2:
- state->prim_mode = ADV7604_PRIM_MODE_COMP;
- break;
- default:
- return -EINVAL;
- }
+ state->mode = input;
disable_input(sd);
- select_input(sd, state->prim_mode);
+ select_input(sd);
- enable_input(sd, state->prim_mode);
+ enable_input(sd);
return 0;
}
@@ -1549,8 +1719,9 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true");
v4l2_info(sd, "CP free run: %s\n",
(!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off"));
- v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n",
- io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f);
+ v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n",
+ io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f,
+ (io_read(sd, 0x01) & 0x70) >> 4);
v4l2_info(sd, "-----Video Timings-----\n");
if (read_stdi(sd, &stdi))
@@ -1712,9 +1883,9 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */
cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */
cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold -
- ADI recommended setting [REF_01 c. 2.3.3] */
+ ADI recommended setting [REF_01, c. 2.3.3] */
cp_write(sd, 0x45, 0x23); /* STDI ch. 2 - LCVS change threshold -
- ADI recommended setting [REF_01 c. 2.3.3] */
+ ADI recommended setting [REF_01, c. 2.3.3] */
cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution
for digital formats */
@@ -1724,11 +1895,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */
io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4);
- state->prim_mode = pdata->prim_mode;
- select_input(sd, pdata->prim_mode);
-
- enable_input(sd, pdata->prim_mode);
-
/* interrupts */
io_write(sd, 0x40, 0xc2); /* Configure INT1 */
io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */
@@ -1883,6 +2049,7 @@ static int adv7604_probe(struct i2c_client *client,
v4l2_err(sd, "failed to create all i2c clients\n");
goto err_i2c;
}
+ state->restart_stdi_once = true;
/* work queues */
state->work_queues = create_singlethread_workqueue(client->name);
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index 13057b966ee9..333ef178d6fb 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -263,9 +263,14 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
if (ret & 1) /* Autoexposure */
ret = reg_write(client, mt9v022->reg->max_total_shutter_width,
rect.height + mt9v022->y_skip_top + 43);
- else
- ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
- rect.height + mt9v022->y_skip_top + 43);
+ /*
+ * If autoexposure is off, there is no need to set
+ * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off
+ * only if the user has set exposure manually, using the
+ * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL.
+ * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH
+ * already contains the correct value.
+ */
}
/* Setup frame format: defaults apart from width and height */
if (!ret)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index bfec9e65aefb..19cbb12a12a2 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -965,8 +965,10 @@ static struct platform_device_id gsc_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, gsc_driver_ids);
static const struct of_device_id exynos_gsc_match[] = {
- { .compatible = "samsung,exynos5250-gsc",
- .data = &gsc_v_100_drvdata, },
+ {
+ .compatible = "samsung,exynos5-gsc",
+ .data = &gsc_v_100_drvdata,
+ },
{},
};
MODULE_DEVICE_TABLE(of, exynos_gsc_match);
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 3c7f00577bd9..c065d040ed94 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -657,8 +657,7 @@ static int gsc_m2m_release(struct file *file)
pr_debug("pid: %d, state: 0x%lx, refcnt= %d",
task_pid_nr(current), gsc->state, gsc->m2m.refcnt);
- if (mutex_lock_interruptible(&gsc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&gsc->lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
gsc_ctrls_delete(ctx);
@@ -732,6 +731,7 @@ int gsc_register_m2m_device(struct gsc_dev *gsc)
gsc->vdev.ioctl_ops = &gsc_m2m_ioctl_ops;
gsc->vdev.release = video_device_release_empty;
gsc->vdev.lock = &gsc->lock;
+ gsc->vdev.vfl_dir = VFL_DIR_M2M;
snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m",
GSC_MODULE_NAME, gsc->id);
diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.h b/drivers/media/platform/exynos-gsc/gsc-regs.h
index 533e9947a925..4678f9a6a4fd 100644
--- a/drivers/media/platform/exynos-gsc/gsc-regs.h
+++ b/drivers/media/platform/exynos-gsc/gsc-regs.h
@@ -40,10 +40,10 @@
#define GSC_IN_ROT_YFLIP (2 << 16)
#define GSC_IN_ROT_XFLIP (1 << 16)
#define GSC_IN_RGB_TYPE_MASK (3 << 14)
-#define GSC_IN_RGB_HD_WIDE (3 << 14)
-#define GSC_IN_RGB_HD_NARROW (2 << 14)
-#define GSC_IN_RGB_SD_WIDE (1 << 14)
-#define GSC_IN_RGB_SD_NARROW (0 << 14)
+#define GSC_IN_RGB_HD_NARROW (3 << 14)
+#define GSC_IN_RGB_HD_WIDE (2 << 14)
+#define GSC_IN_RGB_SD_NARROW (1 << 14)
+#define GSC_IN_RGB_SD_WIDE (0 << 14)
#define GSC_IN_YUV422_1P_ORDER_MASK (1 << 13)
#define GSC_IN_YUV422_1P_ORDER_LSB_Y (0 << 13)
#define GSC_IN_YUV422_1P_OEDER_LSB_C (1 << 13)
@@ -85,10 +85,10 @@
#define GSC_OUT_GLOBAL_ALPHA_MASK (0xff << 24)
#define GSC_OUT_GLOBAL_ALPHA(x) ((x) << 24)
#define GSC_OUT_RGB_TYPE_MASK (3 << 10)
-#define GSC_OUT_RGB_HD_NARROW (3 << 10)
-#define GSC_OUT_RGB_HD_WIDE (2 << 10)
-#define GSC_OUT_RGB_SD_NARROW (1 << 10)
-#define GSC_OUT_RGB_SD_WIDE (0 << 10)
+#define GSC_OUT_RGB_HD_WIDE (3 << 10)
+#define GSC_OUT_RGB_HD_NARROW (2 << 10)
+#define GSC_OUT_RGB_SD_WIDE (1 << 10)
+#define GSC_OUT_RGB_SD_NARROW (0 << 10)
#define GSC_OUT_YUV422_1P_ORDER_MASK (1 << 9)
#define GSC_OUT_YUV422_1P_ORDER_LSB_Y (0 << 9)
#define GSC_OUT_YUV422_1P_OEDER_LSB_C (1 << 9)
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 60181ab96063..aa9df9d71a7b 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1706,7 +1706,7 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
}
static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
if (sub->type != V4L2_EVENT_FRAME_SYNC)
return -EINVAL;
@@ -1719,7 +1719,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
}
static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
return v4l2_event_unsubscribe(fh, sub);
}
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index d7ac76b5c2ae..b8640be692f1 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -1025,7 +1025,7 @@ void omap3isp_stat_dma_isr(struct ispstat *stat)
int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
struct ispstat *stat = v4l2_get_subdevdata(subdev);
@@ -1037,7 +1037,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub)
+ struct v4l2_event_subscription *sub)
{
return v4l2_event_unsubscribe(fh, sub);
}
diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h
index a6fe653eb237..9b7c8654dc8a 100644
--- a/drivers/media/platform/omap3isp/ispstat.h
+++ b/drivers/media/platform/omap3isp/ispstat.h
@@ -147,10 +147,10 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name,
void omap3isp_stat_cleanup(struct ispstat *stat);
int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub);
+ struct v4l2_event_subscription *sub);
int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
struct v4l2_fh *fh,
- const struct v4l2_event_subscription *sub);
+ struct v4l2_event_subscription *sub);
int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable);
int omap3isp_stat_busy(struct ispstat *stat);
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index a0b737fecf13..75cd309035f9 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -792,7 +792,7 @@ isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
}
static int
-isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
{
struct isp_video *video = video_drvdata(file);
struct v4l2_subdev *subdev;
diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig
index 8f090a8f270e..c16b20d86ed2 100644
--- a/drivers/media/platform/s5p-fimc/Kconfig
+++ b/drivers/media/platform/s5p-fimc/Kconfig
@@ -24,6 +24,7 @@ config VIDEO_S5P_FIMC
config VIDEO_S5P_MIPI_CSIS
tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver"
depends on REGULATOR
+ select S5P_SETUP_MIPIPHY
help
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2
receiver (MIPI-CSIS) devices.
diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c
index 367efd164d0f..891ee873c62b 100644
--- a/drivers/media/platform/s5p-fimc/fimc-capture.c
+++ b/drivers/media/platform/s5p-fimc/fimc-capture.c
@@ -556,8 +556,7 @@ static int fimc_capture_close(struct file *file)
dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&fimc->lock);
if (--fimc->vid_cap.refcnt == 0) {
clear_bit(ST_CAPT_BUSY, &fimc->state);
@@ -1736,7 +1735,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc,
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct fimc_vid_buffer);
- vb2_queue_init(q);
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto err_ent;
vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
@@ -1772,9 +1773,13 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
if (ret)
return ret;
+ fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
+
ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
- if (ret)
+ if (ret) {
fimc_unregister_m2m_device(fimc);
+ fimc->pipeline_ops = NULL;
+ }
return ret;
}
@@ -1791,6 +1796,7 @@ static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
if (video_is_registered(&fimc->vid_cap.vfd)) {
video_unregister_device(&fimc->vid_cap.vfd);
media_entity_cleanup(&fimc->vid_cap.vfd.entity);
+ fimc->pipeline_ops = NULL;
}
kfree(fimc->vid_cap.ctx);
fimc->vid_cap.ctx = NULL;
diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c
index 70bcf39de879..1b309a72f09f 100644
--- a/drivers/media/platform/s5p-fimc/fimc-lite.c
+++ b/drivers/media/platform/s5p-fimc/fimc-lite.c
@@ -491,8 +491,7 @@ static int fimc_lite_close(struct file *file)
struct fimc_lite *fimc = video_drvdata(file);
int ret;
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&fimc->lock);
if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
clear_bit(ST_FLITE_IN_USE, &fimc->state);
@@ -1253,7 +1252,9 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
q->buf_struct_size = sizeof(struct flite_buffer);
q->drv_priv = fimc;
- vb2_queue_init(q);
+ ret = vb2_queue_init(q);
+ if (ret < 0)
+ return ret;
fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
@@ -1261,10 +1262,12 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
return ret;
video_set_drvdata(vfd, fimc);
+ fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd);
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
media_entity_cleanup(&vfd->entity);
+ fimc->pipeline_ops = NULL;
return ret;
}
@@ -1283,6 +1286,7 @@ static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
if (video_is_registered(&fimc->vfd)) {
video_unregister_device(&fimc->vfd);
media_entity_cleanup(&fimc->vfd.entity);
+ fimc->pipeline_ops = NULL;
}
}
diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c
index 4500e44f6857..62afed3162ea 100644
--- a/drivers/media/platform/s5p-fimc/fimc-m2m.c
+++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c
@@ -718,8 +718,7 @@ static int fimc_m2m_release(struct file *file)
dbg("pid: %d, state: 0x%lx, refcnt= %d",
task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
- if (mutex_lock_interruptible(&fimc->lock))
- return -ERESTARTSYS;
+ mutex_lock(&fimc->lock);
v4l2_m2m_ctx_release(ctx->m2m_ctx);
fimc_ctrls_delete(ctx);
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
index 80ada5882f62..0531ab70a94c 100644
--- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c
@@ -343,53 +343,50 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
static int fimc_register_callback(struct device *dev, void *p)
{
struct fimc_dev *fimc = dev_get_drvdata(dev);
- struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+ struct v4l2_subdev *sd;
struct fimc_md *fmd = p;
- int ret = 0;
-
- if (!fimc || !fimc->pdev)
- return 0;
+ int ret;
- if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
+ if (fimc == NULL || fimc->id >= FIMC_MAX_DEVS)
return 0;
- fimc->pipeline_ops = &fimc_pipeline_ops;
- fmd->fimc[fimc->pdev->id] = fimc;
+ sd = &fimc->vid_cap.subdev;
sd->grp_id = FIMC_GROUP_ID;
+ v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops);
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
if (ret) {
v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
fimc->id, ret);
+ return ret;
}
- return ret;
+ fmd->fimc[fimc->id] = fimc;
+ return 0;
}
static int fimc_lite_register_callback(struct device *dev, void *p)
{
struct fimc_lite *fimc = dev_get_drvdata(dev);
- struct v4l2_subdev *sd = &fimc->subdev;
struct fimc_md *fmd = p;
int ret;
- if (fimc == NULL)
+ if (fimc == NULL || fimc->index >= FIMC_LITE_MAX_DEVS)
return 0;
- if (fimc->index >= FIMC_LITE_MAX_DEVS)
- return 0;
-
- fimc->pipeline_ops = &fimc_pipeline_ops;
- fmd->fimc_lite[fimc->index] = fimc;
- sd->grp_id = FLITE_GROUP_ID;
+ fimc->subdev.grp_id = FLITE_GROUP_ID;
+ v4l2_set_subdev_hostdata(&fimc->subdev, (void *)&fimc_pipeline_ops);
- ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, &fimc->subdev);
if (ret) {
v4l2_err(&fmd->v4l2_dev,
"Failed to register FIMC-LITE.%d (%d)\n",
fimc->index, ret);
+ return ret;
}
- return ret;
+
+ fmd->fimc_lite[fimc->index] = fimc;
+ return 0;
}
static int csis_register_callback(struct device *dev, void *p)
@@ -407,10 +404,12 @@ static int csis_register_callback(struct device *dev, void *p)
v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name);
id = pdev->id < 0 ? 0 : pdev->id;
- fmd->csis[id].sd = sd;
sd->grp_id = CSIS_GROUP_ID;
+
ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
- if (ret)
+ if (!ret)
+ fmd->csis[id].sd = sd;
+ else
v4l2_err(&fmd->v4l2_dev,
"Failed to register CSIS subdevice: %d\n", ret);
return ret;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 130f4ac8649e..3afe879d54d7 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -381,11 +381,8 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops,
get_consumed_stream, dev);
if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC &&
- s5p_mfc_hw_call(dev->mfc_ops,
- get_dec_frame_type, dev) ==
- S5P_FIMV_DECODE_FRAME_P_FRAME
- && ctx->consumed_stream + STUFF_BYTE <
- src_buf->b->v4l2_planes[0].bytesused) {
+ ctx->consumed_stream + STUFF_BYTE <
+ src_buf->b->v4l2_planes[0].bytesused) {
/* Run MFC again on the same buffer */
mfc_debug(2, "Running again the same buffer\n");
ctx->after_packed_pb = 1;
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 50b5bee3c44e..3a8cfd9fc1bd 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1762,7 +1762,7 @@ int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6);
+ return mfc_read(dev, S5P_FIMV_D_DECODED_LUMA_ADDR_V6);
}
int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 85fd312f0a82..a1c87f0ceaab 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -935,9 +935,10 @@ static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
/* Assume a dull encoder, do all the work ourselves. */
static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
{
+ struct v4l2_crop a_writable = *a;
struct video_device *vdev = video_devdata(file);
struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_rect *rect = &a_writable.c;
struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT};
struct v4l2_pix_format *pix = &vou_dev->pix;
struct sh_vou_geometry geo;
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
index bbe70991d30b..032b8c9097f9 100644
--- a/drivers/media/platform/soc_camera/mx1_camera.c
+++ b/drivers/media/platform/soc_camera/mx1_camera.c
@@ -470,14 +470,6 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd)
pcdev->icd = NULL;
}
-static int mx1_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, video, s_crop, a);
-}
-
static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -689,7 +681,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
.add = mx1_camera_add_device,
.remove = mx1_camera_remove_device,
.set_bus_param = mx1_camera_set_bus_param,
- .set_crop = mx1_camera_set_crop,
.set_fmt = mx1_camera_set_fmt,
.try_fmt = mx1_camera_try_fmt,
.init_videobuf = mx1_camera_init_videobuf,
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 9fd9d1c5b218..9a55f4c4c7f4 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -864,8 +864,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
bytesperline = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
- if (bytesperline < 0)
+ if (bytesperline < 0) {
+ spin_unlock_irqrestore(&pcdev->lock, flags);
return bytesperline;
+ }
/*
* I didn't manage to properly enable/disable the prp
@@ -878,8 +880,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
pcdev->discard_size, &pcdev->discard_buffer_dma,
GFP_KERNEL);
- if (!pcdev->discard_buffer)
+ if (!pcdev->discard_buffer) {
+ spin_unlock_irqrestore(&pcdev->lock, flags);
return -ENOMEM;
+ }
pcdev->buf_discard[0].discard = true;
list_add_tail(&pcdev->buf_discard[0].queue,
@@ -1099,9 +1103,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
}
static int mx2_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop a_writable = *a;
+ struct v4l2_rect *rect = &a_writable.c;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_mbus_framefmt mf;
int ret;
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 3557ac97e430..261f6e9e1b17 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -799,9 +799,10 @@ static inline void stride_align(__u32 *width)
* default g_crop and cropcap from soc_camera.c
*/
static int mx3_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop a_writable = *a;
+ struct v4l2_rect *rect = &a_writable.c;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index fa08c7695ccb..13636a585106 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -1215,9 +1215,9 @@ static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
}
static int omap1_cam_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *crop)
+ const struct v4l2_crop *crop)
{
- struct v4l2_rect *rect = &crop->c;
+ const struct v4l2_rect *rect = &crop->c;
const struct soc_camera_format_xlate *xlate = icd->current_fmt;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 1e3776d08dac..3434ffe79c6e 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -1337,9 +1337,9 @@ static int pxa_camera_check_frame(u32 width, u32 height)
}
static int pxa_camera_set_crop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ const struct v4l2_rect *rect = &a->c;
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct pxa_camera_dev *pcdev = ici->priv;
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 0a24253dcda2..2d8861c0e8f2 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -1182,13 +1182,13 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd)
}
/* Check if any dimension of r1 is smaller than respective one of r2 */
-static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2)
+static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
{
return r1->width < r2->width || r1->height < r2->height;
}
/* Check if r1 fails to cover r2 */
-static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2)
+static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2)
{
return r1->left > r2->left || r1->top > r2->top ||
r1->left + r1->width < r2->left + r2->width ||
@@ -1263,7 +1263,7 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam)
* 3. if (2) failed, try to request the maximum image
*/
static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop,
- const struct v4l2_crop *cam_crop)
+ struct v4l2_crop *cam_crop)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c;
@@ -1519,7 +1519,8 @@ static int client_scale(struct soc_camera_device *icd,
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
const struct v4l2_crop *a)
{
- struct v4l2_rect *rect = &a->c;
+ struct v4l2_crop a_writable = *a;
+ const struct v4l2_rect *rect = &a_writable.c;
struct device *dev = icd->parent;
struct soc_camera_host *ici = to_soc_camera_host(dev);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
@@ -1545,7 +1546,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
* 1. - 2. Apply iterative camera S_CROP for new input window, read back
* actual camera rectangle.
*/
- ret = client_s_crop(icd, a, &cam_crop);
+ ret = client_s_crop(icd, &a_writable, &cam_crop);
if (ret < 0)
return ret;
@@ -1946,7 +1947,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
}
static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
- struct v4l2_crop *a)
+ const struct v4l2_crop *a)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
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 9859d2a2449b..ba51f65204de 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -283,14 +283,13 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
/* 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)
+ adap->pid_filtering && adap->props->pid_filter) {
ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
dvbdmxfeed->pid, (count == 1) ? 1 : 0);
- if (ret < 0)
- dev_err(&d->udev->dev, "%s: pid_filter() " \
- "failed=%d\n", KBUILD_MODNAME,
- ret);
+ if (ret < 0)
+ dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n",
+ KBUILD_MODNAME, ret);
+ }
/* start feeding if it is first pid */
if (adap->feed_count == 1 && count == 1) {
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 0431beed0ef4..5716662b4834 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c
@@ -32,9 +32,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
return -EINVAL;
}
- ret = mutex_lock_interruptible(&d->usb_mutex);
- if (ret < 0)
- return ret;
+ mutex_lock(&d->usb_mutex);
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index adabba8d28bc..093f1acce403 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1346,6 +1346,10 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
&rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
+ { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
+ &rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) },
+ { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7,
+ &rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index 1b48f2094806..f4f9bf84bc7b 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -98,9 +98,9 @@ static irqreturn_t arizona_underclocked(int irq, void *data)
if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
dev_err(arizona->dev, "AIF3 underclocked\n");
- if (val & ARIZONA_AIF3_UNDERCLOCKED_STS)
- dev_err(arizona->dev, "AIF3 underclocked\n");
if (val & ARIZONA_AIF2_UNDERCLOCKED_STS)
+ dev_err(arizona->dev, "AIF2 underclocked\n");
+ if (val & ARIZONA_AIF1_UNDERCLOCKED_STS)
dev_err(arizona->dev, "AIF1 underclocked\n");
if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS)
dev_err(arizona->dev, "ISRC2 underclocked\n");
@@ -415,11 +415,19 @@ int __devinit arizona_dev_init(struct arizona *arizona)
/* If we have a /RESET GPIO we'll already be reset */
if (!arizona->pdata.reset) {
+ regcache_mark_dirty(arizona->regmap);
+
ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0);
if (ret != 0) {
dev_err(dev, "Failed to reset device: %d\n", ret);
goto err_reset;
}
+
+ ret = regcache_sync(arizona->regmap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to sync device: %d\n", ret);
+ goto err_reset;
+ }
}
ret = arizona_wait_for_boot(arizona);
@@ -520,7 +528,7 @@ int __devinit arizona_dev_init(struct arizona *arizona)
break;
case WM5110:
ret = mfd_add_devices(arizona->dev, -1, wm5110_devs,
- ARRAY_SIZE(wm5102_devs), NULL, 0, NULL);
+ ARRAY_SIZE(wm5110_devs), NULL, 0, NULL);
break;
}
diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c
index ef0f2d001df2..b1b009177405 100644
--- a/drivers/mfd/arizona-irq.c
+++ b/drivers/mfd/arizona-irq.c
@@ -178,6 +178,7 @@ int arizona_irq_init(struct arizona *arizona)
switch (arizona->rev) {
case 0:
+ case 1:
ctrlif_error = false;
break;
default:
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 00b8b0f3dfb6..b96661d453aa 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -31,6 +31,7 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/db8500-prcmu.h>
#include <linux/regulator/machine.h>
+#include <linux/cpufreq.h>
#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
@@ -420,9 +421,6 @@ static struct {
static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
-/* Functions definition */
-static void compute_armss_rate(void);
-
/* Spinlocks */
static DEFINE_SPINLOCK(prcmu_lock);
static DEFINE_SPINLOCK(clkout_lock);
@@ -1019,7 +1017,6 @@ int db8500_prcmu_set_arm_opp(u8 opp)
(mb1_transfer.ack.arm_opp != opp))
r = -EIO;
- compute_armss_rate();
mutex_unlock(&mb1_transfer.lock);
return r;
@@ -1169,12 +1166,12 @@ int db8500_prcmu_get_ape_opp(void)
}
/**
- * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
+ * db8500_prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
* @enable: true to request the higher voltage, false to drop a request.
*
* Calls to this function to enable and disable requests must be balanced.
*/
-int prcmu_request_ape_opp_100_voltage(bool enable)
+int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
{
int r = 0;
u8 header;
@@ -1669,13 +1666,8 @@ static unsigned long clock_rate(u8 clock)
else
return 0;
}
-static unsigned long latest_armss_rate;
-static unsigned long armss_rate(void)
-{
- return latest_armss_rate;
-}
-static void compute_armss_rate(void)
+static unsigned long armss_rate(void)
{
u32 r;
unsigned long rate;
@@ -1700,7 +1692,7 @@ static void compute_armss_rate(void)
rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV);
}
- latest_armss_rate = rate;
+ return rate;
}
static unsigned long dsiclk_rate(u8 n)
@@ -1820,6 +1812,35 @@ static long round_clock_rate(u8 clock, unsigned long rate)
return rounded_rate;
}
+/* CPU FREQ table, may be changed due to if MAX_OPP is supported. */
+static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
+ { .frequency = 200000, .index = ARM_EXTCLK,},
+ { .frequency = 400000, .index = ARM_50_OPP,},
+ { .frequency = 800000, .index = ARM_100_OPP,},
+ { .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */
+ { .frequency = CPUFREQ_TABLE_END,},
+};
+
+static long round_armss_rate(unsigned long rate)
+{
+ long freq = 0;
+ int i = 0;
+
+ /* cpufreq table frequencies is in KHz. */
+ rate = rate / 1000;
+
+ /* Find the corresponding arm opp from the cpufreq table. */
+ while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
+ freq = db8500_cpufreq_table[i].frequency;
+ if (freq == rate)
+ break;
+ i++;
+ }
+
+ /* Return the last valid value, even if a match was not found. */
+ return freq * 1000;
+}
+
#define MIN_PLL_VCO_RATE 600000000ULL
#define MAX_PLL_VCO_RATE 1680640000ULL
@@ -1891,6 +1912,8 @@ long prcmu_round_clock_rate(u8 clock, unsigned long rate)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
return round_clock_rate(clock, rate);
+ else if (clock == PRCMU_ARMSS)
+ return round_armss_rate(rate);
else if (clock == PRCMU_PLLDSI)
return round_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
@@ -1950,6 +1973,27 @@ static void set_clock_rate(u8 clock, unsigned long rate)
spin_unlock_irqrestore(&clk_mgt_lock, flags);
}
+static int set_armss_rate(unsigned long rate)
+{
+ int i = 0;
+
+ /* cpufreq table frequencies is in KHz. */
+ rate = rate / 1000;
+
+ /* Find the corresponding arm opp from the cpufreq table. */
+ while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
+ if (db8500_cpufreq_table[i].frequency == rate)
+ break;
+ i++;
+ }
+
+ if (db8500_cpufreq_table[i].frequency != rate)
+ return -EINVAL;
+
+ /* Set the new arm opp. */
+ return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].index);
+}
+
static int set_plldsi_rate(unsigned long rate)
{
unsigned long src_rate;
@@ -2030,6 +2074,8 @@ int prcmu_set_clock_rate(u8 clock, unsigned long rate)
{
if (clock < PRCMU_NUM_REG_CLOCKS)
set_clock_rate(clock, rate);
+ else if (clock == PRCMU_ARMSS)
+ return set_armss_rate(rate);
else if (clock == PRCMU_PLLDSI)
return set_plldsi_rate(rate);
else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK))
@@ -2754,8 +2800,6 @@ void __init db8500_prcmu_early_init(void)
init_completion(&mb5_transfer.work);
INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
-
- compute_armss_rate();
}
static void __init init_prcm_registers(void)
@@ -3020,6 +3064,8 @@ static struct mfd_cell db8500_prcmu_devs[] = {
{
.name = "cpufreq-u8500",
.of_compatible = "stericsson,cpufreq-u8500",
+ .platform_data = &db8500_cpufreq_table,
+ .pdata_size = sizeof(db8500_cpufreq_table),
},
{
.name = "ab8500-core",
@@ -3030,6 +3076,14 @@ static struct mfd_cell db8500_prcmu_devs[] = {
},
};
+static void db8500_prcmu_update_cpufreq(void)
+{
+ if (prcmu_has_arm_maxopp()) {
+ db8500_cpufreq_table[3].frequency = 1000000;
+ db8500_cpufreq_table[3].index = ARM_MAX_OPP;
+ }
+}
+
/**
* prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
*
@@ -3074,6 +3128,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
if (cpu_is_u8500v20_or_later())
prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+ db8500_prcmu_update_cpufreq();
+
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL);
if (err) {
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 4ae642320205..a071a8643a47 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -671,7 +671,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
}
if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) {
- child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0,
+ child = add_child(SUB_CHIP_ID1, "twl6030-pwm", NULL, 0,
false, 0, 0);
if (IS_ERR(child))
return PTR_ERR(child);
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index ad733d76207a..cdd1173ed4e9 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -672,7 +672,8 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base)
irq = sih_mod + twl4030_irq_base;
irq_set_handler_data(irq, agent);
agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name);
- status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
+ status = request_threaded_irq(irq, NULL, handle_twl4030_sih,
+ IRQF_EARLY_RESUME,
agent->irq_name ?: sih->name, NULL);
dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name,
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index 01b9255ed631..14490cc785d2 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -43,6 +43,7 @@ static const struct reg_default wm5102_reva_patch[] = {
{ 0x479, 0x0A30 },
{ 0x47B, 0x0810 },
{ 0x47D, 0x0510 },
+ { 0x4D1, 0x017F },
{ 0x500, 0x000D },
{ 0x507, 0x1820 },
{ 0x508, 0x1820 },
@@ -52,524 +53,6 @@ static const struct reg_default wm5102_reva_patch[] = {
{ 0x580, 0x000D },
{ 0x587, 0x1820 },
{ 0x588, 0x1820 },
- { 0x101, 0x8140 },
- { 0x3000, 0x2225 },
- { 0x3001, 0x3a03 },
- { 0x3002, 0x0225 },
- { 0x3003, 0x0801 },
- { 0x3004, 0x6249 },
- { 0x3005, 0x0c04 },
- { 0x3006, 0x0225 },
- { 0x3007, 0x5901 },
- { 0x3008, 0xe249 },
- { 0x3009, 0x030d },
- { 0x300a, 0x0249 },
- { 0x300b, 0x2c01 },
- { 0x300c, 0xe249 },
- { 0x300d, 0x4342 },
- { 0x300e, 0xe249 },
- { 0x300f, 0x73c0 },
- { 0x3010, 0x4249 },
- { 0x3011, 0x0c00 },
- { 0x3012, 0x0225 },
- { 0x3013, 0x1f01 },
- { 0x3014, 0x0225 },
- { 0x3015, 0x1e01 },
- { 0x3016, 0x0225 },
- { 0x3017, 0xfa00 },
- { 0x3018, 0x0000 },
- { 0x3019, 0xf000 },
- { 0x301a, 0x0000 },
- { 0x301b, 0xf000 },
- { 0x301c, 0x0000 },
- { 0x301d, 0xf000 },
- { 0x301e, 0x0000 },
- { 0x301f, 0xf000 },
- { 0x3020, 0x0000 },
- { 0x3021, 0xf000 },
- { 0x3022, 0x0000 },
- { 0x3023, 0xf000 },
- { 0x3024, 0x0000 },
- { 0x3025, 0xf000 },
- { 0x3026, 0x0000 },
- { 0x3027, 0xf000 },
- { 0x3028, 0x0000 },
- { 0x3029, 0xf000 },
- { 0x302a, 0x0000 },
- { 0x302b, 0xf000 },
- { 0x302c, 0x0000 },
- { 0x302d, 0xf000 },
- { 0x302e, 0x0000 },
- { 0x302f, 0xf000 },
- { 0x3030, 0x0225 },
- { 0x3031, 0x1a01 },
- { 0x3032, 0x0225 },
- { 0x3033, 0x1e00 },
- { 0x3034, 0x0225 },
- { 0x3035, 0x1f00 },
- { 0x3036, 0x6225 },
- { 0x3037, 0xf800 },
- { 0x3038, 0x0000 },
- { 0x3039, 0xf000 },
- { 0x303a, 0x0000 },
- { 0x303b, 0xf000 },
- { 0x303c, 0x0000 },
- { 0x303d, 0xf000 },
- { 0x303e, 0x0000 },
- { 0x303f, 0xf000 },
- { 0x3040, 0x2226 },
- { 0x3041, 0x3a03 },
- { 0x3042, 0x0226 },
- { 0x3043, 0x0801 },
- { 0x3044, 0x6249 },
- { 0x3045, 0x0c06 },
- { 0x3046, 0x0226 },
- { 0x3047, 0x5901 },
- { 0x3048, 0xe249 },
- { 0x3049, 0x030d },
- { 0x304a, 0x0249 },
- { 0x304b, 0x2c01 },
- { 0x304c, 0xe249 },
- { 0x304d, 0x4342 },
- { 0x304e, 0xe249 },
- { 0x304f, 0x73c0 },
- { 0x3050, 0x4249 },
- { 0x3051, 0x0c00 },
- { 0x3052, 0x0226 },
- { 0x3053, 0x1f01 },
- { 0x3054, 0x0226 },
- { 0x3055, 0x1e01 },
- { 0x3056, 0x0226 },
- { 0x3057, 0xfa00 },
- { 0x3058, 0x0000 },
- { 0x3059, 0xf000 },
- { 0x305a, 0x0000 },
- { 0x305b, 0xf000 },
- { 0x305c, 0x0000 },
- { 0x305d, 0xf000 },
- { 0x305e, 0x0000 },
- { 0x305f, 0xf000 },
- { 0x3060, 0x0000 },
- { 0x3061, 0xf000 },
- { 0x3062, 0x0000 },
- { 0x3063, 0xf000 },
- { 0x3064, 0x0000 },
- { 0x3065, 0xf000 },
- { 0x3066, 0x0000 },
- { 0x3067, 0xf000 },
- { 0x3068, 0x0000 },
- { 0x3069, 0xf000 },
- { 0x306a, 0x0000 },
- { 0x306b, 0xf000 },
- { 0x306c, 0x0000 },
- { 0x306d, 0xf000 },
- { 0x306e, 0x0000 },
- { 0x306f, 0xf000 },
- { 0x3070, 0x0226 },
- { 0x3071, 0x1a01 },
- { 0x3072, 0x0226 },
- { 0x3073, 0x1e00 },
- { 0x3074, 0x0226 },
- { 0x3075, 0x1f00 },
- { 0x3076, 0x6226 },
- { 0x3077, 0xf800 },
- { 0x3078, 0x0000 },
- { 0x3079, 0xf000 },
- { 0x307a, 0x0000 },
- { 0x307b, 0xf000 },
- { 0x307c, 0x0000 },
- { 0x307d, 0xf000 },
- { 0x307e, 0x0000 },
- { 0x307f, 0xf000 },
- { 0x3080, 0x2227 },
- { 0x3081, 0x3a03 },
- { 0x3082, 0x0227 },
- { 0x3083, 0x0801 },
- { 0x3084, 0x6255 },
- { 0x3085, 0x0c04 },
- { 0x3086, 0x0227 },
- { 0x3087, 0x5901 },
- { 0x3088, 0xe255 },
- { 0x3089, 0x030d },
- { 0x308a, 0x0255 },
- { 0x308b, 0x2c01 },
- { 0x308c, 0xe255 },
- { 0x308d, 0x4342 },
- { 0x308e, 0xe255 },
- { 0x308f, 0x73c0 },
- { 0x3090, 0x4255 },
- { 0x3091, 0x0c00 },
- { 0x3092, 0x0227 },
- { 0x3093, 0x1f01 },
- { 0x3094, 0x0227 },
- { 0x3095, 0x1e01 },
- { 0x3096, 0x0227 },
- { 0x3097, 0xfa00 },
- { 0x3098, 0x0000 },
- { 0x3099, 0xf000 },
- { 0x309a, 0x0000 },
- { 0x309b, 0xf000 },
- { 0x309c, 0x0000 },
- { 0x309d, 0xf000 },
- { 0x309e, 0x0000 },
- { 0x309f, 0xf000 },
- { 0x30a0, 0x0000 },
- { 0x30a1, 0xf000 },
- { 0x30a2, 0x0000 },
- { 0x30a3, 0xf000 },
- { 0x30a4, 0x0000 },
- { 0x30a5, 0xf000 },
- { 0x30a6, 0x0000 },
- { 0x30a7, 0xf000 },
- { 0x30a8, 0x0000 },
- { 0x30a9, 0xf000 },
- { 0x30aa, 0x0000 },
- { 0x30ab, 0xf000 },
- { 0x30ac, 0x0000 },
- { 0x30ad, 0xf000 },
- { 0x30ae, 0x0000 },
- { 0x30af, 0xf000 },
- { 0x30b0, 0x0227 },
- { 0x30b1, 0x1a01 },
- { 0x30b2, 0x0227 },
- { 0x30b3, 0x1e00 },
- { 0x30b4, 0x0227 },
- { 0x30b5, 0x1f00 },
- { 0x30b6, 0x6227 },
- { 0x30b7, 0xf800 },
- { 0x30b8, 0x0000 },
- { 0x30b9, 0xf000 },
- { 0x30ba, 0x0000 },
- { 0x30bb, 0xf000 },
- { 0x30bc, 0x0000 },
- { 0x30bd, 0xf000 },
- { 0x30be, 0x0000 },
- { 0x30bf, 0xf000 },
- { 0x30c0, 0x2228 },
- { 0x30c1, 0x3a03 },
- { 0x30c2, 0x0228 },
- { 0x30c3, 0x0801 },
- { 0x30c4, 0x6255 },
- { 0x30c5, 0x0c06 },
- { 0x30c6, 0x0228 },
- { 0x30c7, 0x5901 },
- { 0x30c8, 0xe255 },
- { 0x30c9, 0x030d },
- { 0x30ca, 0x0255 },
- { 0x30cb, 0x2c01 },
- { 0x30cc, 0xe255 },
- { 0x30cd, 0x4342 },
- { 0x30ce, 0xe255 },
- { 0x30cf, 0x73c0 },
- { 0x30d0, 0x4255 },
- { 0x30d1, 0x0c00 },
- { 0x30d2, 0x0228 },
- { 0x30d3, 0x1f01 },
- { 0x30d4, 0x0228 },
- { 0x30d5, 0x1e01 },
- { 0x30d6, 0x0228 },
- { 0x30d7, 0xfa00 },
- { 0x30d8, 0x0000 },
- { 0x30d9, 0xf000 },
- { 0x30da, 0x0000 },
- { 0x30db, 0xf000 },
- { 0x30dc, 0x0000 },
- { 0x30dd, 0xf000 },
- { 0x30de, 0x0000 },
- { 0x30df, 0xf000 },
- { 0x30e0, 0x0000 },
- { 0x30e1, 0xf000 },
- { 0x30e2, 0x0000 },
- { 0x30e3, 0xf000 },
- { 0x30e4, 0x0000 },
- { 0x30e5, 0xf000 },
- { 0x30e6, 0x0000 },
- { 0x30e7, 0xf000 },
- { 0x30e8, 0x0000 },
- { 0x30e9, 0xf000 },
- { 0x30ea, 0x0000 },
- { 0x30eb, 0xf000 },
- { 0x30ec, 0x0000 },
- { 0x30ed, 0xf000 },
- { 0x30ee, 0x0000 },
- { 0x30ef, 0xf000 },
- { 0x30f0, 0x0228 },
- { 0x30f1, 0x1a01 },
- { 0x30f2, 0x0228 },
- { 0x30f3, 0x1e00 },
- { 0x30f4, 0x0228 },
- { 0x30f5, 0x1f00 },
- { 0x30f6, 0x6228 },
- { 0x30f7, 0xf800 },
- { 0x30f8, 0x0000 },
- { 0x30f9, 0xf000 },
- { 0x30fa, 0x0000 },
- { 0x30fb, 0xf000 },
- { 0x30fc, 0x0000 },
- { 0x30fd, 0xf000 },
- { 0x30fe, 0x0000 },
- { 0x30ff, 0xf000 },
- { 0x3100, 0x222b },
- { 0x3101, 0x3a03 },
- { 0x3102, 0x222b },
- { 0x3103, 0x5803 },
- { 0x3104, 0xe26f },
- { 0x3105, 0x030d },
- { 0x3106, 0x626f },
- { 0x3107, 0x2c01 },
- { 0x3108, 0xe26f },
- { 0x3109, 0x4342 },
- { 0x310a, 0xe26f },
- { 0x310b, 0x73c0 },
- { 0x310c, 0x026f },
- { 0x310d, 0x0c00 },
- { 0x310e, 0x022b },
- { 0x310f, 0x1f01 },
- { 0x3110, 0x022b },
- { 0x3111, 0x1e01 },
- { 0x3112, 0x022b },
- { 0x3113, 0xfa00 },
- { 0x3114, 0x0000 },
- { 0x3115, 0xf000 },
- { 0x3116, 0x0000 },
- { 0x3117, 0xf000 },
- { 0x3118, 0x0000 },
- { 0x3119, 0xf000 },
- { 0x311a, 0x0000 },
- { 0x311b, 0xf000 },
- { 0x311c, 0x0000 },
- { 0x311d, 0xf000 },
- { 0x311e, 0x0000 },
- { 0x311f, 0xf000 },
- { 0x3120, 0x022b },
- { 0x3121, 0x0a01 },
- { 0x3122, 0x022b },
- { 0x3123, 0x1e00 },
- { 0x3124, 0x022b },
- { 0x3125, 0x1f00 },
- { 0x3126, 0x622b },
- { 0x3127, 0xf800 },
- { 0x3128, 0x0000 },
- { 0x3129, 0xf000 },
- { 0x312a, 0x0000 },
- { 0x312b, 0xf000 },
- { 0x312c, 0x0000 },
- { 0x312d, 0xf000 },
- { 0x312e, 0x0000 },
- { 0x312f, 0xf000 },
- { 0x3130, 0x0000 },
- { 0x3131, 0xf000 },
- { 0x3132, 0x0000 },
- { 0x3133, 0xf000 },
- { 0x3134, 0x0000 },
- { 0x3135, 0xf000 },
- { 0x3136, 0x0000 },
- { 0x3137, 0xf000 },
- { 0x3138, 0x0000 },
- { 0x3139, 0xf000 },
- { 0x313a, 0x0000 },
- { 0x313b, 0xf000 },
- { 0x313c, 0x0000 },
- { 0x313d, 0xf000 },
- { 0x313e, 0x0000 },
- { 0x313f, 0xf000 },
- { 0x3140, 0x0000 },
- { 0x3141, 0xf000 },
- { 0x3142, 0x0000 },
- { 0x3143, 0xf000 },
- { 0x3144, 0x0000 },
- { 0x3145, 0xf000 },
- { 0x3146, 0x0000 },
- { 0x3147, 0xf000 },
- { 0x3148, 0x0000 },
- { 0x3149, 0xf000 },
- { 0x314a, 0x0000 },
- { 0x314b, 0xf000 },
- { 0x314c, 0x0000 },
- { 0x314d, 0xf000 },
- { 0x314e, 0x0000 },
- { 0x314f, 0xf000 },
- { 0x3150, 0x0000 },
- { 0x3151, 0xf000 },
- { 0x3152, 0x0000 },
- { 0x3153, 0xf000 },
- { 0x3154, 0x0000 },
- { 0x3155, 0xf000 },
- { 0x3156, 0x0000 },
- { 0x3157, 0xf000 },
- { 0x3158, 0x0000 },
- { 0x3159, 0xf000 },
- { 0x315a, 0x0000 },
- { 0x315b, 0xf000 },
- { 0x315c, 0x0000 },
- { 0x315d, 0xf000 },
- { 0x315e, 0x0000 },
- { 0x315f, 0xf000 },
- { 0x3160, 0x0000 },
- { 0x3161, 0xf000 },
- { 0x3162, 0x0000 },
- { 0x3163, 0xf000 },
- { 0x3164, 0x0000 },
- { 0x3165, 0xf000 },
- { 0x3166, 0x0000 },
- { 0x3167, 0xf000 },
- { 0x3168, 0x0000 },
- { 0x3169, 0xf000 },
- { 0x316a, 0x0000 },
- { 0x316b, 0xf000 },
- { 0x316c, 0x0000 },
- { 0x316d, 0xf000 },
- { 0x316e, 0x0000 },
- { 0x316f, 0xf000 },
- { 0x3170, 0x0000 },
- { 0x3171, 0xf000 },
- { 0x3172, 0x0000 },
- { 0x3173, 0xf000 },
- { 0x3174, 0x0000 },
- { 0x3175, 0xf000 },
- { 0x3176, 0x0000 },
- { 0x3177, 0xf000 },
- { 0x3178, 0x0000 },
- { 0x3179, 0xf000 },
- { 0x317a, 0x0000 },
- { 0x317b, 0xf000 },
- { 0x317c, 0x0000 },
- { 0x317d, 0xf000 },
- { 0x317e, 0x0000 },
- { 0x317f, 0xf000 },
- { 0x3180, 0x2001 },
- { 0x3181, 0xf101 },
- { 0x3182, 0x0000 },
- { 0x3183, 0xf000 },
- { 0x3184, 0x0000 },
- { 0x3185, 0xf000 },
- { 0x3186, 0x0000 },
- { 0x3187, 0xf000 },
- { 0x3188, 0x0000 },
- { 0x3189, 0xf000 },
- { 0x318a, 0x0000 },
- { 0x318b, 0xf000 },
- { 0x318c, 0x0000 },
- { 0x318d, 0xf000 },
- { 0x318e, 0x0000 },
- { 0x318f, 0xf000 },
- { 0x3190, 0x0000 },
- { 0x3191, 0xf000 },
- { 0x3192, 0x0000 },
- { 0x3193, 0xf000 },
- { 0x3194, 0x0000 },
- { 0x3195, 0xf000 },
- { 0x3196, 0x0000 },
- { 0x3197, 0xf000 },
- { 0x3198, 0x0000 },
- { 0x3199, 0xf000 },
- { 0x319a, 0x0000 },
- { 0x319b, 0xf000 },
- { 0x319c, 0x0000 },
- { 0x319d, 0xf000 },
- { 0x319e, 0x0000 },
- { 0x319f, 0xf000 },
- { 0x31a0, 0x0000 },
- { 0x31a1, 0xf000 },
- { 0x31a2, 0x0000 },
- { 0x31a3, 0xf000 },
- { 0x31a4, 0x0000 },
- { 0x31a5, 0xf000 },
- { 0x31a6, 0x0000 },
- { 0x31a7, 0xf000 },
- { 0x31a8, 0x0000 },
- { 0x31a9, 0xf000 },
- { 0x31aa, 0x0000 },
- { 0x31ab, 0xf000 },
- { 0x31ac, 0x0000 },
- { 0x31ad, 0xf000 },
- { 0x31ae, 0x0000 },
- { 0x31af, 0xf000 },
- { 0x31b0, 0x0000 },
- { 0x31b1, 0xf000 },
- { 0x31b2, 0x0000 },
- { 0x31b3, 0xf000 },
- { 0x31b4, 0x0000 },
- { 0x31b5, 0xf000 },
- { 0x31b6, 0x0000 },
- { 0x31b7, 0xf000 },
- { 0x31b8, 0x0000 },
- { 0x31b9, 0xf000 },
- { 0x31ba, 0x0000 },
- { 0x31bb, 0xf000 },
- { 0x31bc, 0x0000 },
- { 0x31bd, 0xf000 },
- { 0x31be, 0x0000 },
- { 0x31bf, 0xf000 },
- { 0x31c0, 0x0000 },
- { 0x31c1, 0xf000 },
- { 0x31c2, 0x0000 },
- { 0x31c3, 0xf000 },
- { 0x31c4, 0x0000 },
- { 0x31c5, 0xf000 },
- { 0x31c6, 0x0000 },
- { 0x31c7, 0xf000 },
- { 0x31c8, 0x0000 },
- { 0x31c9, 0xf000 },
- { 0x31ca, 0x0000 },
- { 0x31cb, 0xf000 },
- { 0x31cc, 0x0000 },
- { 0x31cd, 0xf000 },
- { 0x31ce, 0x0000 },
- { 0x31cf, 0xf000 },
- { 0x31d0, 0x0000 },
- { 0x31d1, 0xf000 },
- { 0x31d2, 0x0000 },
- { 0x31d3, 0xf000 },
- { 0x31d4, 0x0000 },
- { 0x31d5, 0xf000 },
- { 0x31d6, 0x0000 },
- { 0x31d7, 0xf000 },
- { 0x31d8, 0x0000 },
- { 0x31d9, 0xf000 },
- { 0x31da, 0x0000 },
- { 0x31db, 0xf000 },
- { 0x31dc, 0x0000 },
- { 0x31dd, 0xf000 },
- { 0x31de, 0x0000 },
- { 0x31df, 0xf000 },
- { 0x31e0, 0x0000 },
- { 0x31e1, 0xf000 },
- { 0x31e2, 0x0000 },
- { 0x31e3, 0xf000 },
- { 0x31e4, 0x0000 },
- { 0x31e5, 0xf000 },
- { 0x31e6, 0x0000 },
- { 0x31e7, 0xf000 },
- { 0x31e8, 0x0000 },
- { 0x31e9, 0xf000 },
- { 0x31ea, 0x0000 },
- { 0x31eb, 0xf000 },
- { 0x31ec, 0x0000 },
- { 0x31ed, 0xf000 },
- { 0x31ee, 0x0000 },
- { 0x31ef, 0xf000 },
- { 0x31f0, 0x0000 },
- { 0x31f1, 0xf000 },
- { 0x31f2, 0x0000 },
- { 0x31f3, 0xf000 },
- { 0x31f4, 0x0000 },
- { 0x31f5, 0xf000 },
- { 0x31f6, 0x0000 },
- { 0x31f7, 0xf000 },
- { 0x31f8, 0x0000 },
- { 0x31f9, 0xf000 },
- { 0x31fa, 0x0000 },
- { 0x31fb, 0xf000 },
- { 0x31fc, 0x0000 },
- { 0x31fd, 0xf000 },
- { 0x31fe, 0x0000 },
- { 0x31ff, 0xf000 },
- { 0x024d, 0xff50 },
- { 0x0252, 0xff50 },
- { 0x0259, 0x0112 },
- { 0x025e, 0x0112 },
- { 0x101, 0x0304 },
{ 0x80, 0x0000 },
};
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 172a768036d8..21056b9ef0a0 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECERASE 0x80
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
+#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
static DEFINE_MUTEX(block_mutex);
@@ -126,6 +127,10 @@ enum mmc_blk_status {
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+ struct mmc_blk_data *md);
+static int get_card_status(struct mmc_card *card, u32 *status, int retries);
+
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@@ -357,6 +362,38 @@ out:
return ERR_PTR(err);
}
+static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
+ u32 retries_max)
+{
+ int err;
+ u32 retry_count = 0;
+
+ if (!status || !retries_max)
+ return -EINVAL;
+
+ do {
+ err = get_card_status(card, status, 5);
+ if (err)
+ break;
+
+ if (!R1_STATUS(*status) &&
+ (R1_CURRENT_STATE(*status) != R1_STATE_PRG))
+ break; /* RPMB programming operation complete */
+
+ /*
+ * Rechedule to give the MMC device a chance to continue
+ * processing the previous command without being polled too
+ * frequently.
+ */
+ usleep_range(1000, 5000);
+ } while (++retry_count < retries_max);
+
+ if (retry_count == retries_max)
+ err = -EPERM;
+
+ return err;
+}
+
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
+ int is_rpmb = false;
+ u32 status = 0;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
@@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_err;
}
+ if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
+ is_rpmb = true;
+
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
@@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mmc_claim_host(card->host);
+ err = mmc_blk_part_switch(card, md);
+ if (err)
+ goto cmd_rel_host;
+
if (idata->ic.is_acmd) {
err = mmc_app_cmd(card->host, card);
if (err)
goto cmd_rel_host;
}
+ if (is_rpmb) {
+ err = mmc_set_blockcount(card, data.blocks,
+ idata->ic.write_flag & (1 << 31));
+ if (err)
+ goto cmd_rel_host;
+ }
+
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
}
+ if (is_rpmb) {
+ /*
+ * Ensure RPMB command has completed by polling CMD13
+ * "Send Status".
+ */
+ err = ioctl_rpmb_card_status_poll(card, &status, 5);
+ if (err)
+ dev_err(mmc_dev(card->host),
+ "%s: Card Status=0x%08X, error %d\n",
+ __func__, status, err);
+ }
+
cmd_rel_host:
mmc_release_host(card->host);
@@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card,
*/
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
u32 status;
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
do {
int err = get_card_status(card, &status, 5);
if (err) {
@@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
req->rq_disk->disk_name, err);
return MMC_BLK_CMD_ERR;
}
+
+ /* Timeout if the device never becomes ready for data
+ * and never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state!"\
+ " %s %s\n", mmc_hostname(card->host),
+ req->rq_disk->disk_name, __func__);
+
+ return MMC_BLK_CMD_ERR;
+ }
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
@@ -1504,6 +1583,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
md->disk->queue = md->queue.queue;
md->disk->driverfs_dev = parent;
set_disk_ro(md->disk, md->read_only || default_ro);
+ if (area_type & MMC_BLK_DATA_AREA_RPMB)
+ md->disk->flags |= GENHD_FL_NO_PART_SCAN;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index e360a979857d..fadf52eb5d70 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d)
if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
+
+ /*
+ * Current request becomes previous request
+ * and vice versa.
+ */
+ mq->mqrq_prev->brq.mrq.data = NULL;
+ mq->mqrq_prev->req = NULL;
+ tmp = mq->mqrq_prev;
+ mq->mqrq_prev = mq->mqrq_cur;
+ mq->mqrq_cur = tmp;
} else {
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
@@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d)
schedule();
down(&mq->thread_sem);
}
-
- /* Current request becomes previous request and vice versa. */
- mq->mqrq_prev->brq.mrq.data = NULL;
- mq->mqrq_prev->req = NULL;
- tmp = mq->mqrq_prev;
- mq->mqrq_prev = mq->mqrq_cur;
- mq->mqrq_cur = tmp;
} while (1);
up(&mq->thread_sem);
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 9b68933f27e7..420cb6753c1e 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev)
sdio_free_common_cis(card);
- if (card->info)
- kfree(card->info);
+ kfree(card->info);
kfree(card);
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 06c42cfb7c34..aaed7687cf09 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -42,6 +42,9 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+/* If the device is not responding */
+#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
{
struct mmc_command cmd = {0};
unsigned int qty = 0;
+ unsigned long timeout;
int err;
/*
@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if (mmc_host_is_spi(card->host))
goto out;
+ timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
err = -EIO;
goto out;
}
+
+ /* Timeout if the device never becomes ready for data and
+ * never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ err = -EIO;
+ goto out;
+ }
+
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
+ (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
return err;
}
@@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);
+int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+ bool is_rel_write)
+{
+ struct mmc_command cmd = {0};
+
+ cmd.opcode = MMC_SET_BLOCK_COUNT;
+ cmd.arg = blockcount & 0x0000FFFF;
+ if (is_rel_write)
+ cmd.arg |= 1 << 31;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+ return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blockcount);
+
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index d96c643dde1c..35c2f85b1956 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data)
}
seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ str = "3.30 V";
+ break;
+ case MMC_SIGNAL_VOLTAGE_180:
+ str = "1.80 V";
+ break;
+ case MMC_SIGNAL_VOLTAGE_120:
+ str = "1.20 V";
+ break;
+ default:
+ str = "invalid";
+ break;
+ }
+ seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
+
return 0;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7cc46382fd64..e6e39111e05b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card)
{
struct mmc_host *host = card->host;
u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
- unsigned int caps = host->caps, caps2 = host->caps2;
+ u32 caps = host->caps, caps2 = host->caps2;
unsigned int hs_max_dtr = 0;
if (card_type & EXT_CSD_CARD_TYPE_26)
@@ -491,6 +491,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+
+ /*
+ * RPMB regions are defined in multiples of 128K.
+ */
+ card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
+ if (ext_csd[EXT_CSD_RPMB_MULT]) {
+ mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
+ EXT_CSD_PART_CONFIG_ACC_RPMB,
+ "rpmb", 0, false,
+ MMC_BLK_DATA_AREA_RPMB);
+ }
}
card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
@@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
+MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
+MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
+ &dev_attr_raw_rpmb_size_mult.attr,
+ &dev_attr_rel_sectors.attr,
NULL,
};
@@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
+ if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+ max_dtr = 52000000;
} else if (max_dtr > card->csd.max_dtr) {
max_dtr = card->csd.max_dtr;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index a0e172042e65..6d8f7012d73a 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -21,6 +21,8 @@
#include "core.h"
#include "mmc_ops.h"
+#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
@@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
{
int err;
struct mmc_command cmd = {0};
+ unsigned long timeout;
u32 status;
BUG_ON(!card);
@@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
return 0;
/* Must check status to be sure of no errors */
+ timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do {
err = mmc_send_status(card, &status);
if (err)
@@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
break;
if (mmc_host_is_spi(card->host))
break;
+
+ /* Timeout if the device never leaves the program state. */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ return -ETIMEDOUT;
+ }
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(card->host)) {
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 6bf68799fe97..5e57048e2c1d 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev)
}
#ifdef CONFIG_PM
+
+#ifdef CONFIG_PM_SLEEP
+static int pm_no_operation(struct device *dev)
+{
+ /*
+ * Prevent the PM core from calling SDIO device drivers' suspend
+ * callback routines, which it is not supposed to do, by using this
+ * empty function as the bus type suspend callaback for SDIO.
+ */
+ return 0;
+}
+#endif
+
static const struct dev_pm_ops sdio_bus_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
@@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev)
sdio_free_func_cis(func);
- if (func->info)
- kfree(func->info);
+ kfree(func->info);
kfree(func);
}
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
index 8f6f5ac131fc..78cb4d5d9d58 100644
--- a/drivers/mmc/core/sdio_io.c
+++ b/drivers/mmc/core/sdio_io.c
@@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size);
*/
static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
{
- unsigned mval = min(func->card->host->max_seg_size,
- func->card->host->max_blk_size);
+ unsigned mval = func->card->host->max_blk_size;
if (mmc_blksz_for_byte_mode(func->card))
mval = min(mval, func->cur_blksize);
@@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
/* Do the bulk of the transfer using block mode (if supported). */
if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
/* Blocks per command is limited by host count, host transfer
- * size (we only use a single sg entry) and the maximum for
- * IO_RW_EXTENDED of 511 blocks. */
- max_blocks = min(func->card->host->max_blk_count,
- func->card->host->max_seg_size / func->cur_blksize);
- max_blocks = min(max_blocks, 511u);
+ * size and the maximum for IO_RW_EXTENDED of 511 blocks. */
+ max_blocks = min(func->card->host->max_blk_count, 511u);
while (remainder >= func->cur_blksize) {
unsigned blocks;
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index d29e20630eed..62508b457c4f 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
- struct scatterlist sg;
+ struct scatterlist sg, *sg_ptr;
+ struct sg_table sgtable;
+ unsigned int nents, left_size, i;
+ unsigned int seg_size = card->host->max_seg_size;
BUG_ON(!card);
BUG_ON(fn > 7);
@@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
/* Code in host drivers/fwk assumes that "blocks" always is >=1 */
data.blocks = blocks ? blocks : 1;
data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
- sg_init_one(&sg, buf, data.blksz * data.blocks);
+ left_size = data.blksz * data.blocks;
+ nents = (left_size - 1) / seg_size + 1;
+ if (nents > 1) {
+ if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
+ return -ENOMEM;
+
+ data.sg = sgtable.sgl;
+ data.sg_len = nents;
+
+ for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
+ sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)),
+ min(seg_size, left_size),
+ offset_in_page(buf + (i * seg_size)));
+ left_size = left_size - seg_size;
+ }
+ } else {
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, buf, left_size);
+ }
mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
+ if (nents > 1)
+ sg_free_table(&sgtable);
+
if (cmd.error)
return cmd.error;
if (data.error)
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 08c6b3dfe080..16a1c0b6f264 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -27,7 +27,13 @@ struct mmc_gpio {
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
- mmc_detect_change(dev_id, msecs_to_jiffies(100));
+ struct mmc_host *host = dev_id;
+
+ if (host->ops->card_event)
+ host->ops->card_event(host);
+
+ mmc_detect_change(host, msecs_to_jiffies(200));
+
return IRQ_HANDLED;
}
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 9bf10e7bbfaf..83eb1e06ff76 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -270,26 +270,8 @@ config MMC_AU1X
If unsure, say N.
-choice
- prompt "Atmel SD/MMC Driver"
- depends on AVR32 || ARCH_AT91
- default MMC_ATMELMCI if AVR32
- help
- Choose which driver to use for the Atmel MCI Silicon
-
-config MMC_AT91
- tristate "AT91 SD/MMC Card Interface support (DEPRECATED)"
- depends on ARCH_AT91
- help
- This selects the AT91 MCI controller. This driver will
- be removed soon (for more information have a look to
- Documentation/feature-removal-schedule.txt). Please use
- MMC_ATMEL_MCI.
-
- If unsure, say N.
-
config MMC_ATMELMCI
- tristate "Atmel Multimedia Card Interface support"
+ tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"
depends on AVR32 || ARCH_AT91
help
This selects the Atmel Multimedia Card Interface driver. If
@@ -298,8 +280,6 @@ config MMC_ATMELMCI
If unsure, say N.
-endchoice
-
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support"
depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
@@ -621,3 +601,14 @@ config MMC_USHC
Note: These controllers only support SDIO cards and do not
support MMC or SD memory cards.
+
+config MMC_WMT
+ tristate "Wondermedia SD/MMC Host Controller support"
+ depends on ARCH_VT8500
+ default y
+ help
+ This selects support for the SD/MMC Host Controller on
+ Wondermedia WM8505/WM8650 based SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wmt-sdmmc.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 17ad0a7ba40b..39d5e1234709 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -17,7 +17,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o
-obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_MSM) += msm_sdcc.o
@@ -45,6 +44,7 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o
+obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
deleted file mode 100644
index 74bed0fc23e7..000000000000
--- a/drivers/mmc/host/at91_mci.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
- *
- * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
- * Copyright (C) 2006 Malcolm Noyes
- *
- * 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 is the AT91 MCI driver that has been tested with both MMC cards
- and SD-cards. Boards that support write protect are now supported.
- The CCAT91SBC001 board does not support SD cards.
-
- The three entry points are at91_mci_request, at91_mci_set_ios
- and at91_mci_get_ro.
-
- SET IOS
- This configures the device to put it into the correct mode and clock speed
- required.
-
- MCI REQUEST
- MCI request processes the commands sent in the mmc_request structure. This
- can consist of a processing command and a stop command in the case of
- multiple block transfers.
-
- There are three main types of request, commands, reads and writes.
-
- Commands are straight forward. The command is submitted to the controller and
- the request function returns. When the controller generates an interrupt to indicate
- the command is finished, the response to the command are read and the mmc_request_done
- function called to end the request.
-
- Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
- controller to manage the transfers.
-
- A read is done from the controller directly to the scatterlist passed in from the request.
- Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
- swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug.
-
- The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
- A write is slightly different in that the bytes to write are read from the scatterlist
- into a dma memory buffer (this is in case the source buffer should be read only). The
- entire write buffer is then done from this single dma memory buffer.
-
- The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
-
- GET RO
- Gets the status of the write protect pin, if available.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-#include <linux/gfp.h>
-#include <linux/highmem.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/gpio.h>
-
-#include <mach/board.h>
-#include <mach/cpu.h>
-
-#include "at91_mci.h"
-
-#define DRIVER_NAME "at91_mci"
-
-static inline int at91mci_is_mci1rev2xx(void)
-{
- return ( cpu_is_at91sam9260()
- || cpu_is_at91sam9263()
- || cpu_is_at91sam9rl()
- || cpu_is_at91sam9g10()
- || cpu_is_at91sam9g20()
- );
-}
-
-#define FL_SENT_COMMAND (1 << 0)
-#define FL_SENT_STOP (1 << 1)
-
-#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
- | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \
- | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
-
-#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
-#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
-
-#define MCI_BLKSIZE 512
-#define MCI_MAXBLKSIZE 4095
-#define MCI_BLKATONCE 256
-#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE)
-
-/*
- * Low level type for this driver
- */
-struct at91mci_host
-{
- struct mmc_host *mmc;
- struct mmc_command *cmd;
- struct mmc_request *request;
-
- void __iomem *baseaddr;
- int irq;
-
- struct at91_mmc_data *board;
- int present;
-
- struct clk *mci_clk;
-
- /*
- * Flag indicating when the command has been sent. This is used to
- * work out whether or not to send the stop
- */
- unsigned int flags;
- /* flag for current bus settings */
- u32 bus_mode;
-
- /* DMA buffer used for transmitting */
- unsigned int* buffer;
- dma_addr_t physical_address;
- unsigned int total_length;
-
- /* Latest in the scatterlist that has been enabled for transfer, but not freed */
- int in_use_index;
-
- /* Latest in the scatterlist that has been enabled for transfer */
- int transfer_index;
-
- /* Timer for timeouts */
- struct timer_list timer;
-};
-
-/*
- * Reset the controller and restore most of the state
- */
-static void at91_reset_host(struct at91mci_host *host)
-{
- unsigned long flags;
- u32 mr;
- u32 sdcr;
- u32 dtor;
- u32 imr;
-
- local_irq_save(flags);
- imr = at91_mci_read(host, AT91_MCI_IMR);
-
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
- /* save current state */
- mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
- sdcr = at91_mci_read(host, AT91_MCI_SDCR);
- dtor = at91_mci_read(host, AT91_MCI_DTOR);
-
- /* reset the controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-
- /* restore state */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(host, AT91_MCI_MR, mr);
- at91_mci_write(host, AT91_MCI_SDCR, sdcr);
- at91_mci_write(host, AT91_MCI_DTOR, dtor);
- at91_mci_write(host, AT91_MCI_IER, imr);
-
- /* make sure sdio interrupts will fire */
- at91_mci_read(host, AT91_MCI_SR);
-
- local_irq_restore(flags);
-}
-
-static void at91_timeout_timer(unsigned long data)
-{
- struct at91mci_host *host;
-
- host = (struct at91mci_host *)data;
-
- if (host->request) {
- dev_err(host->mmc->parent, "Timeout waiting end of packet\n");
-
- if (host->cmd && host->cmd->data) {
- host->cmd->data->error = -ETIMEDOUT;
- } else {
- if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- else
- host->request->cmd->error = -ETIMEDOUT;
- }
-
- at91_reset_host(host);
- mmc_request_done(host->mmc, host->request);
- }
-}
-
-/*
- * Copy from sg to a dma block - used for transfers
- */
-static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
-{
- unsigned int len, i, size;
- unsigned *dmabuf = host->buffer;
-
- size = data->blksz * data->blocks;
- len = data->sg_len;
-
- /* MCI1 rev2xx Data Write Operation and number of bytes erratum */
- if (at91mci_is_mci1rev2xx())
- if (host->total_length == 12)
- memset(dmabuf, 0, 12);
-
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-
- sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-
- if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- int index;
-
- for (index = 0; index < (amount / 4); index++)
- *dmabuf++ = swab32(sgbuffer[index]);
- } else {
- char *tmpv = (char *)dmabuf;
- memcpy(tmpv, sgbuffer, amount);
- tmpv += amount;
- dmabuf = (unsigned *)tmpv;
- }
-
- kunmap_atomic(sgbuffer);
-
- if (size == 0)
- break;
- }
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
- BUG_ON(size != 0);
-}
-
-/*
- * Handle after a dma read
- */
-static void at91_mci_post_dma_read(struct at91mci_host *host)
-{
- struct mmc_command *cmd;
- struct mmc_data *data;
- unsigned int len, i, size;
- unsigned *dmabuf = host->buffer;
-
- pr_debug("post dma read\n");
-
- cmd = host->cmd;
- if (!cmd) {
- pr_debug("no command\n");
- return;
- }
-
- data = cmd->data;
- if (!data) {
- pr_debug("no data\n");
- return;
- }
-
- size = data->blksz * data->blocks;
- len = data->sg_len;
-
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-
- sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-
- if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- int index;
- for (index = 0; index < (amount / 4); index++)
- sgbuffer[index] = swab32(*dmabuf++);
- } else {
- char *tmpv = (char *)dmabuf;
- memcpy(sgbuffer, tmpv, amount);
- tmpv += amount;
- dmabuf = (unsigned *)tmpv;
- }
-
- flush_kernel_dcache_page(sg_page(sg));
- kunmap_atomic(sgbuffer);
- data->bytes_xfered += amount;
- if (size == 0)
- break;
- }
-
- pr_debug("post dma read done\n");
-}
-
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- pr_debug("Handling the transmit\n");
-
- /* Disable the transfer */
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- /* Now wait for cmd ready */
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-
- cmd = host->cmd;
- if (!cmd) return;
-
- data = cmd->data;
- if (!data) return;
-
- if (cmd->data->blocks > 1) {
- pr_debug("multiple write : wait for BLKE...\n");
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
- } else
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-}
-
-/*
- * Update bytes transfered count during a write operation
- */
-static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
-{
- struct mmc_data *data;
-
- /* always deal with the effective request (and not the current cmd) */
-
- if (host->request->cmd && host->request->cmd->error != 0)
- return;
-
- if (host->request->data) {
- data = host->request->data;
- if (data->flags & MMC_DATA_WRITE) {
- /* card is in IDLE mode now */
- pr_debug("-> bytes_xfered %d, total_length = %d\n",
- data->bytes_xfered, host->total_length);
- data->bytes_xfered = data->blksz * data->blocks;
- }
- }
-}
-
-
-/*Handle after command sent ready*/
-static int at91_mci_handle_cmdrdy(struct at91mci_host *host)
-{
- if (!host->cmd)
- return 1;
- else if (!host->cmd->data) {
- if (host->flags & FL_SENT_STOP) {
- /*After multi block write, we must wait for NOTBUSY*/
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
- } else return 1;
- } else if (host->cmd->data->flags & MMC_DATA_WRITE) {
- /*After sendding multi-block-write command, start DMA transfer*/
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE);
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
- }
-
- /* command not completed, have to wait */
- return 0;
-}
-
-
-/*
- * Enable the controller
- */
-static void at91_mci_enable(struct at91mci_host *host)
-{
- unsigned int mr;
-
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
- at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
- mr = AT91_MCI_PDCMODE | 0x34a;
-
- if (at91mci_is_mci1rev2xx())
- mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;
-
- at91_mci_write(host, AT91_MCI_MR, mr);
-
- /* use Slot A or B (only one at same time) */
- at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
-}
-
-/*
- * Disable the controller
- */
-static void at91_mci_disable(struct at91mci_host *host)
-{
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-}
-
-/*
- * Send a command
- */
-static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
- unsigned int cmdr, mr;
- unsigned int block_length;
- struct mmc_data *data = cmd->data;
-
- unsigned int blocks;
- unsigned int ier = 0;
-
- host->cmd = cmd;
-
- /* Needed for leaving busy state before CMD1 */
- if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
- pr_debug("Clearing timeout\n");
- at91_mci_write(host, AT91_MCI_ARGR, 0);
- at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
- while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
- /* spin */
- pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
- }
- }
-
- cmdr = cmd->opcode;
-
- if (mmc_resp_type(cmd) == MMC_RSP_NONE)
- cmdr |= AT91_MCI_RSPTYP_NONE;
- else {
- /* if a response is expected then allow maximum response latancy */
- cmdr |= AT91_MCI_MAXLAT;
- /* set 136 bit response for R2, 48 bit response otherwise */
- if (mmc_resp_type(cmd) == MMC_RSP_R2)
- cmdr |= AT91_MCI_RSPTYP_136;
- else
- cmdr |= AT91_MCI_RSPTYP_48;
- }
-
- if (data) {
-
- if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
- if (data->blksz & 0x3) {
- pr_debug("Unsupported block size\n");
- cmd->error = -EINVAL;
- mmc_request_done(host->mmc, host->request);
- return;
- }
- if (data->flags & MMC_DATA_STREAM) {
- pr_debug("Stream commands not supported\n");
- cmd->error = -EINVAL;
- mmc_request_done(host->mmc, host->request);
- return;
- }
- }
-
- block_length = data->blksz;
- blocks = data->blocks;
-
- /* always set data start - also set direction flag for read */
- if (data->flags & MMC_DATA_READ)
- cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
- else if (data->flags & MMC_DATA_WRITE)
- cmdr |= AT91_MCI_TRCMD_START;
-
- if (cmd->opcode == SD_IO_RW_EXTENDED) {
- cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
- } else {
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->blocks > 1)
- cmdr |= AT91_MCI_TRTYP_MULTIPLE;
- }
- }
- else {
- block_length = 0;
- blocks = 0;
- }
-
- if (host->flags & FL_SENT_STOP)
- cmdr |= AT91_MCI_TRCMD_STOP;
-
- if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
- cmdr |= AT91_MCI_OPDCMD;
-
- /*
- * Set the arguments and send the command
- */
- pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
- cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
- if (!data) {
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
- at91_mci_write(host, ATMEL_PDC_RPR, 0);
- at91_mci_write(host, ATMEL_PDC_RCR, 0);
- at91_mci_write(host, ATMEL_PDC_RNPR, 0);
- at91_mci_write(host, ATMEL_PDC_RNCR, 0);
- at91_mci_write(host, ATMEL_PDC_TPR, 0);
- at91_mci_write(host, ATMEL_PDC_TCR, 0);
- at91_mci_write(host, ATMEL_PDC_TNPR, 0);
- at91_mci_write(host, ATMEL_PDC_TNCR, 0);
- ier = AT91_MCI_CMDRDY;
- } else {
- /* zero block length and PDC mode */
- mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
- mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
- mr |= (block_length << 16);
- mr |= AT91_MCI_PDCMODE;
- at91_mci_write(host, AT91_MCI_MR, mr);
-
- if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
- at91_mci_write(host, AT91_MCI_BLKR,
- AT91_MCI_BLKR_BCNT(blocks) |
- AT91_MCI_BLKR_BLKLEN(block_length));
-
- /*
- * Disable the PDC controller
- */
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- data->bytes_xfered = 0;
- host->transfer_index = 0;
- host->in_use_index = 0;
- if (cmdr & AT91_MCI_TRDIR) {
- /*
- * Handle a read
- */
- host->total_length = 0;
-
- at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
- at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
- (blocks * block_length) : (blocks * block_length) / 4);
- at91_mci_write(host, ATMEL_PDC_RNPR, 0);
- at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-
- ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
- }
- else {
- /*
- * Handle a write
- */
- host->total_length = block_length * blocks;
- /*
- * MCI1 rev2xx Data Write Operation and
- * number of bytes erratum
- */
- if (at91mci_is_mci1rev2xx())
- if (host->total_length < 12)
- host->total_length = 12;
-
- at91_mci_sg_to_dma(host, data);
-
- pr_debug("Transmitting %d bytes\n", host->total_length);
-
- at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
- at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
- host->total_length : host->total_length / 4);
-
- ier = AT91_MCI_CMDRDY;
- }
- }
- }
-
- /*
- * Send the command and then enable the PDC - not the other way round as
- * the data sheet says
- */
-
- at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
- at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- if (cmdr & AT91_MCI_TRDIR)
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
- }
-
- /* Enable selected interrupts */
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
-}
-
-/*
- * Process the next step in the request
- */
-static void at91_mci_process_next(struct at91mci_host *host)
-{
- if (!(host->flags & FL_SENT_COMMAND)) {
- host->flags |= FL_SENT_COMMAND;
- at91_mci_send_command(host, host->request->cmd);
- }
- else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
- host->flags |= FL_SENT_STOP;
- at91_mci_send_command(host, host->request->stop);
- } else {
- del_timer(&host->timer);
- /* the at91rm9200 mci controller hangs after some transfers,
- * and the workaround is to reset it after each transfer.
- */
- if (cpu_is_at91rm9200())
- at91_reset_host(host);
- mmc_request_done(host->mmc, host->request);
- }
-}
-
-/*
- * Handle a command that has been completed
- */
-static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status)
-{
- struct mmc_command *cmd = host->cmd;
- struct mmc_data *data = cmd->data;
-
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
- cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
- cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
- cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
- cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
- pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
- status, at91_mci_read(host, AT91_MCI_SR),
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
- if (status & AT91_MCI_ERRORS) {
- if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
- cmd->error = 0;
- }
- else {
- if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) {
- if (data) {
- if (status & AT91_MCI_DTOE)
- data->error = -ETIMEDOUT;
- else if (status & AT91_MCI_DCRCE)
- data->error = -EILSEQ;
- }
- } else {
- if (status & AT91_MCI_RTOE)
- cmd->error = -ETIMEDOUT;
- else if (status & AT91_MCI_RCRCE)
- cmd->error = -EILSEQ;
- else
- cmd->error = -EIO;
- }
-
- pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n",
- cmd->error, data ? data->error : 0,
- cmd->opcode, cmd->retries);
- }
- }
- else
- cmd->error = 0;
-
- at91_mci_process_next(host);
-}
-
-/*
- * Handle an MMC request
- */
-static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct at91mci_host *host = mmc_priv(mmc);
- host->request = mrq;
- host->flags = 0;
-
- /* more than 1s timeout needed with slow SD cards */
- mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
-
- at91_mci_process_next(host);
-}
-
-/*
- * Set the IOS
- */
-static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- int clkdiv;
- struct at91mci_host *host = mmc_priv(mmc);
- unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
- host->bus_mode = ios->bus_mode;
-
- if (ios->clock == 0) {
- /* Disable the MCI controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
- clkdiv = 0;
- }
- else {
- /* Enable the MCI controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
- if ((at91_master_clock % (ios->clock * 2)) == 0)
- clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
- else
- clkdiv = (at91_master_clock / ios->clock) / 2;
-
- pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
- at91_master_clock / (2 * (clkdiv + 1)));
- }
- if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
- pr_debug("MMC: Setting controller bus width to 4\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
- }
- else {
- pr_debug("MMC: Setting controller bus width to 1\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
-
- /* Set the clock divider */
- at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
- /* maybe switch power to the card */
- if (gpio_is_valid(host->board->vcc_pin)) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- gpio_set_value(host->board->vcc_pin, 0);
- break;
- case MMC_POWER_UP:
- gpio_set_value(host->board->vcc_pin, 1);
- break;
- case MMC_POWER_ON:
- break;
- default:
- WARN_ON(1);
- }
- }
-}
-
-/*
- * Handle an interrupt
- */
-static irqreturn_t at91_mci_irq(int irq, void *devid)
-{
- struct at91mci_host *host = devid;
- int completed = 0;
- unsigned int int_status, int_mask;
-
- int_status = at91_mci_read(host, AT91_MCI_SR);
- int_mask = at91_mci_read(host, AT91_MCI_IMR);
-
- pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
- int_status & int_mask);
-
- int_status = int_status & int_mask;
-
- if (int_status & AT91_MCI_ERRORS) {
- completed = 1;
-
- if (int_status & AT91_MCI_UNRE)
- pr_debug("MMC: Underrun error\n");
- if (int_status & AT91_MCI_OVRE)
- pr_debug("MMC: Overrun error\n");
- if (int_status & AT91_MCI_DTOE)
- pr_debug("MMC: Data timeout\n");
- if (int_status & AT91_MCI_DCRCE)
- pr_debug("MMC: CRC error in data\n");
- if (int_status & AT91_MCI_RTOE)
- pr_debug("MMC: Response timeout\n");
- if (int_status & AT91_MCI_RENDE)
- pr_debug("MMC: Response end bit error\n");
- if (int_status & AT91_MCI_RCRCE)
- pr_debug("MMC: Response CRC error\n");
- if (int_status & AT91_MCI_RDIRE)
- pr_debug("MMC: Response direction error\n");
- if (int_status & AT91_MCI_RINDE)
- pr_debug("MMC: Response index error\n");
- } else {
- /* Only continue processing if no errors */
-
- if (int_status & AT91_MCI_TXBUFE) {
- pr_debug("TX buffer empty\n");
- at91_mci_handle_transmitted(host);
- }
-
- if (int_status & AT91_MCI_ENDRX) {
- pr_debug("ENDRX\n");
- at91_mci_post_dma_read(host);
- }
-
- if (int_status & AT91_MCI_RXBUFF) {
- pr_debug("RX buffer full\n");
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX);
- completed = 1;
- }
-
- if (int_status & AT91_MCI_ENDTX)
- pr_debug("Transmit has ended\n");
-
- if (int_status & AT91_MCI_NOTBUSY) {
- pr_debug("Card is ready\n");
- at91_mci_update_bytes_xfered(host);
- completed = 1;
- }
-
- if (int_status & AT91_MCI_DTIP)
- pr_debug("Data transfer in progress\n");
-
- if (int_status & AT91_MCI_BLKE) {
- pr_debug("Block transfer has ended\n");
- if (host->request->data && host->request->data->blocks > 1) {
- /* multi block write : complete multi write
- * command and send stop */
- completed = 1;
- } else {
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
- }
- }
-
- if (int_status & AT91_MCI_SDIOIRQA)
- mmc_signal_sdio_irq(host->mmc);
-
- if (int_status & AT91_MCI_SDIOIRQB)
- mmc_signal_sdio_irq(host->mmc);
-
- if (int_status & AT91_MCI_TXRDY)
- pr_debug("Ready to transmit\n");
-
- if (int_status & AT91_MCI_RXRDY)
- pr_debug("Ready to receive\n");
-
- if (int_status & AT91_MCI_CMDRDY) {
- pr_debug("Command ready\n");
- completed = at91_mci_handle_cmdrdy(host);
- }
- }
-
- if (completed) {
- pr_debug("Completed command\n");
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
- at91_mci_completed_command(host, int_status);
- } else
- at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
-{
- struct at91mci_host *host = _host;
- int present;
-
- /* entering this ISR means that we have configured det_pin:
- * we can use its value in board structure */
- present = !gpio_get_value(host->board->det_pin);
-
- /*
- * we expect this irq on both insert and remove,
- * and use a short delay to debounce.
- */
- if (present != host->present) {
- host->present = present;
- pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
- present ? "insert" : "remove");
- if (!present) {
- pr_debug("****** Resetting SD-card bus width ******\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
- /* 0.5s needed because of early card detect switch firing */
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
- }
- return IRQ_HANDLED;
-}
-
-static int at91_mci_get_ro(struct mmc_host *mmc)
-{
- struct at91mci_host *host = mmc_priv(mmc);
-
- if (gpio_is_valid(host->board->wp_pin))
- return !!gpio_get_value(host->board->wp_pin);
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct at91mci_host *host = mmc_priv(mmc);
-
- pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc),
- host->board->slot_b ? 'B':'A', enable ? "enable" : "disable");
- at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR,
- host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA);
-
-}
-
-static const struct mmc_host_ops at91_mci_ops = {
- .request = at91_mci_request,
- .set_ios = at91_mci_set_ios,
- .get_ro = at91_mci_get_ro,
- .enable_sdio_irq = at91_mci_enable_sdio_irq,
-};
-
-/*
- * Probe for the device
- */
-static int __init at91_mci_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct at91mci_host *host;
- struct resource *res;
- int ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "couldn't allocate mmc host\n");
- goto fail6;
- }
-
- mmc->ops = &at91_mci_ops;
- mmc->f_min = 375000;
- mmc->f_max = 25000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = 0;
-
- mmc->max_blk_size = MCI_MAXBLKSIZE;
- mmc->max_blk_count = MCI_BLKATONCE;
- mmc->max_req_size = MCI_BUFSIZE;
- mmc->max_segs = MCI_BLKATONCE;
- mmc->max_seg_size = MCI_BUFSIZE;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->bus_mode = 0;
- host->board = pdev->dev.platform_data;
- if (host->board->wire4) {
- if (at91mci_is_mci1rev2xx())
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- else
- dev_warn(&pdev->dev, "4 wire bus mode not supported"
- " - using 1 wire\n");
- }
-
- host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE,
- &host->physical_address, GFP_KERNEL);
- if (!host->buffer) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "Can't allocate transmit buffer\n");
- goto fail5;
- }
-
- /* Add SDIO capability when available */
- if (at91mci_is_mci1rev2xx()) {
- /* at91mci MCI1 rev2xx sdio interrupt erratum */
- if (host->board->wire4 || !host->board->slot_b)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- }
-
- /*
- * Reserve GPIOs ... board init code makes sure these pins are set
- * up as GPIOs with the right direction (input, except for vcc)
- */
- if (gpio_is_valid(host->board->det_pin)) {
- ret = gpio_request(host->board->det_pin, "mmc_detect");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
- goto fail4b;
- }
- }
- if (gpio_is_valid(host->board->wp_pin)) {
- ret = gpio_request(host->board->wp_pin, "mmc_wp");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n");
- goto fail4;
- }
- }
- if (gpio_is_valid(host->board->vcc_pin)) {
- ret = gpio_request(host->board->vcc_pin, "mmc_vcc");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n");
- goto fail3;
- }
- }
-
- /*
- * Get Clock
- */
- host->mci_clk = clk_get(&pdev->dev, "mci_clk");
- if (IS_ERR(host->mci_clk)) {
- ret = -ENODEV;
- dev_dbg(&pdev->dev, "no mci_clk?\n");
- goto fail2;
- }
-
- /*
- * Map I/O region
- */
- host->baseaddr = ioremap(res->start, resource_size(res));
- if (!host->baseaddr) {
- ret = -ENOMEM;
- goto fail1;
- }
-
- /*
- * Reset hardware
- */
- clk_enable(host->mci_clk); /* Enable the peripheral clock */
- at91_mci_disable(host);
- at91_mci_enable(host);
-
- /*
- * Allocate the MCI interrupt
- */
- host->irq = platform_get_irq(pdev, 0);
- ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret) {
- dev_dbg(&pdev->dev, "request MCI interrupt failed\n");
- goto fail0;
- }
-
- setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);
-
- platform_set_drvdata(pdev, mmc);
-
- /*
- * Add host to MMC layer
- */
- if (gpio_is_valid(host->board->det_pin)) {
- host->present = !gpio_get_value(host->board->det_pin);
- }
- else
- host->present = -1;
-
- mmc_add_host(mmc);
-
- /*
- * monitor card insertion/removal if we can
- */
- if (gpio_is_valid(host->board->det_pin)) {
- ret = request_irq(gpio_to_irq(host->board->det_pin),
- at91_mmc_det_irq, 0, mmc_hostname(mmc), host);
- if (ret)
- dev_warn(&pdev->dev, "request MMC detect irq failed\n");
- else
- device_init_wakeup(&pdev->dev, 1);
- }
-
- pr_debug("Added MCI driver\n");
-
- return 0;
-
-fail0:
- clk_disable(host->mci_clk);
- iounmap(host->baseaddr);
-fail1:
- clk_put(host->mci_clk);
-fail2:
- if (gpio_is_valid(host->board->vcc_pin))
- gpio_free(host->board->vcc_pin);
-fail3:
- if (gpio_is_valid(host->board->wp_pin))
- gpio_free(host->board->wp_pin);
-fail4:
- if (gpio_is_valid(host->board->det_pin))
- gpio_free(host->board->det_pin);
-fail4b:
- if (host->buffer)
- dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
- host->buffer, host->physical_address);
-fail5:
- mmc_free_host(mmc);
-fail6:
- release_mem_region(res->start, resource_size(res));
- dev_err(&pdev->dev, "probe failed, err %d\n", ret);
- return ret;
-}
-
-/*
- * Remove a device
- */
-static int __exit at91_mci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host;
- struct resource *res;
-
- if (!mmc)
- return -1;
-
- host = mmc_priv(mmc);
-
- if (host->buffer)
- dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
- host->buffer, host->physical_address);
-
- if (gpio_is_valid(host->board->det_pin)) {
- if (device_can_wakeup(&pdev->dev))
- free_irq(gpio_to_irq(host->board->det_pin), host);
- device_init_wakeup(&pdev->dev, 0);
- gpio_free(host->board->det_pin);
- }
-
- at91_mci_disable(host);
- del_timer_sync(&host->timer);
- mmc_remove_host(mmc);
- free_irq(host->irq, host);
-
- clk_disable(host->mci_clk); /* Disable the peripheral clock */
- clk_put(host->mci_clk);
-
- if (gpio_is_valid(host->board->vcc_pin))
- gpio_free(host->board->vcc_pin);
- if (gpio_is_valid(host->board->wp_pin))
- gpio_free(host->board->wp_pin);
-
- iounmap(host->baseaddr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- mmc_free_host(mmc);
- platform_set_drvdata(pdev, NULL);
- pr_debug("MCI Removed\n");
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
- enable_irq_wake(host->board->det_pin);
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- return ret;
-}
-
-static int at91_mci_resume(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
- disable_irq_wake(host->board->det_pin);
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-#else
-#define at91_mci_suspend NULL
-#define at91_mci_resume NULL
-#endif
-
-static struct platform_driver at91_mci_driver = {
- .remove = __exit_p(at91_mci_remove),
- .suspend = at91_mci_suspend,
- .resume = at91_mci_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init at91_mci_init(void)
-{
- return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
-}
-
-static void __exit at91_mci_exit(void)
-{
- platform_driver_unregister(&at91_mci_driver);
-}
-
-module_init(at91_mci_init);
-module_exit(at91_mci_exit);
-
-MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
-MODULE_AUTHOR("Nick Randell");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_mci");
diff --git a/drivers/mmc/host/at91_mci.h b/drivers/mmc/host/at91_mci.h
deleted file mode 100644
index eec3a6b1c2bc..000000000000
--- a/drivers/mmc/host/at91_mci.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * drivers/mmc/host/at91_mci.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * MultiMedia Card Interface (MCI) registers.
- * Based on AT91RM9200 datasheet revision F.
- *
- * This program is free software; you can redistribute it and/or modify
- * 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 AT91_MCI_H
-#define AT91_MCI_H
-
-#define AT91_MCI_CR 0x00 /* Control Register */
-#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */
-#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */
-#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */
-#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */
-#define AT91_MCI_SWRST (1 << 7) /* Software Reset */
-
-#define AT91_MCI_MR 0x04 /* Mode Register */
-#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */
-#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */
-#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */
-#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */
-#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */
-#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */
-#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */
-#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */
-
-#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */
-#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */
-#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */
-#define AT91_MCI_DTOMUL_1 (0 << 4)
-#define AT91_MCI_DTOMUL_16 (1 << 4)
-#define AT91_MCI_DTOMUL_128 (2 << 4)
-#define AT91_MCI_DTOMUL_256 (3 << 4)
-#define AT91_MCI_DTOMUL_1K (4 << 4)
-#define AT91_MCI_DTOMUL_4K (5 << 4)
-#define AT91_MCI_DTOMUL_64K (6 << 4)
-#define AT91_MCI_DTOMUL_1M (7 << 4)
-
-#define AT91_MCI_SDCR 0x0c /* SD Card Register */
-#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */
-#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */
-
-#define AT91_MCI_ARGR 0x10 /* Argument Register */
-
-#define AT91_MCI_CMDR 0x14 /* Command Register */
-#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */
-#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */
-#define AT91_MCI_RSPTYP_NONE (0 << 6)
-#define AT91_MCI_RSPTYP_48 (1 << 6)
-#define AT91_MCI_RSPTYP_136 (2 << 6)
-#define AT91_MCI_SPCMD (7 << 8) /* Special Command */
-#define AT91_MCI_SPCMD_NONE (0 << 8)
-#define AT91_MCI_SPCMD_INIT (1 << 8)
-#define AT91_MCI_SPCMD_SYNC (2 << 8)
-#define AT91_MCI_SPCMD_ICMD (4 << 8)
-#define AT91_MCI_SPCMD_IRESP (5 << 8)
-#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */
-#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */
-#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */
-#define AT91_MCI_TRCMD_NONE (0 << 16)
-#define AT91_MCI_TRCMD_START (1 << 16)
-#define AT91_MCI_TRCMD_STOP (2 << 16)
-#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */
-#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */
-#define AT91_MCI_TRTYP_BLOCK (0 << 19)
-#define AT91_MCI_TRTYP_MULTIPLE (1 << 19)
-#define AT91_MCI_TRTYP_STREAM (2 << 19)
-#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19)
-#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19)
-
-#define AT91_MCI_BLKR 0x18 /* Block Register */
-#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */
-#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */
-
-#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */
-#define AT91_MCR_RDR 0x30 /* Receive Data Register */
-#define AT91_MCR_TDR 0x34 /* Transmit Data Register */
-
-#define AT91_MCI_SR 0x40 /* Status Register */
-#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */
-#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */
-#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */
-#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */
-#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */
-#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */
-#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */
-#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */
-#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */
-#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */
-#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */
-#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */
-#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */
-#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */
-#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */
-#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */
-#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */
-#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */
-#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */
-#define AT91_MCI_OVRE (1 << 30) /* Overrun */
-#define AT91_MCI_UNRE (1 << 31) /* Underrun */
-
-#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */
-#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */
-#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */
-
-#endif
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
index edb37e9135ae..53a09cbb2c7c 100644
--- a/drivers/mmc/host/dw_mmc-pci.c
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {
.name = "dw_mmc_pci",
.id_table = dw_mci_pci_id,
.probe = dw_mci_pci_probe,
- .remove = dw_mci_pci_remove,
+ .remove = __devexit_p(dw_mci_pci_remove),
.driver = {
.pm = &dw_mci_pci_pmops
},
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 917936bee5d5..4e133709e33d 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
static struct platform_driver dw_mci_pltfm_driver = {
- .remove = __exit_p(dw_mci_pltfm_remove),
+ .probe = dw_mci_pltfm_probe,
+ .remove = __devexit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dw_mmc",
.of_match_table = of_match_ptr(dw_mci_pltfm_match),
@@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
},
};
-static int __init dw_mci_init(void)
-{
- return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
-}
-
-static void __exit dw_mci_exit(void)
-{
- platform_driver_unregister(&dw_mci_pltfm_driver);
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
+module_platform_driver(dw_mci_pltfm_driver);
MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
MODULE_AUTHOR("NXP Semiconductor VietNam");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index c0667c8af2bd..323c5022c2ca 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct mmc_data *data;
struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_drv_data *drv_data = slot->host->drv_data;
+ const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 cmdr;
cmd->error = -EINPROGRESS;
@@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
cmd, arg, cmd_status);
}
-static void dw_mci_setup_bus(struct dw_mci_slot *slot)
+static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
{
struct dw_mci *host = slot->host;
u32 div;
u32 clk_en_a;
- if (slot->clock != host->current_speed) {
+ if (slot->clock != host->current_speed || force_clkinit) {
div = host->bus_hz / slot->clock;
if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)
/*
@@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
if (host->pdata->select_slot)
host->pdata->select_slot(slot->id);
- /* Slot specific timing and width adjustment */
- dw_mci_setup_bus(slot);
-
host->cur_slot = slot;
host->mrq = mrq;
@@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_drv_data *drv_data = slot->host->drv_data;
+ const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 regs;
- /* set default 1 bit mode */
- slot->ctype = SDMMC_CTYPE_1BIT;
-
switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- slot->ctype = SDMMC_CTYPE_1BIT;
- break;
case MMC_BUS_WIDTH_4:
slot->ctype = SDMMC_CTYPE_4BIT;
break;
case MMC_BUS_WIDTH_8:
slot->ctype = SDMMC_CTYPE_8BIT;
break;
+ default:
+ /* set default 1 bit mode */
+ slot->ctype = SDMMC_CTYPE_1BIT;
}
regs = mci_readl(slot->host, UHS_REG);
@@ -812,6 +806,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (drv_data && drv_data->set_ios)
drv_data->set_ios(slot->host, ios);
+ /* Slot specific timing and width adjustment */
+ dw_mci_setup_bus(slot, false);
+
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
@@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
- struct dw_mci_drv_data *drv_data = host->drv_data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
int ctrl_id, ret;
u8 bus_width;
@@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
+ if (host->pdata->pm_caps)
+ mmc->pm_caps = host->pdata->pm_caps;
+
if (host->dev->of_node) {
ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
if (ctrl_id < 0)
@@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
- host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+ host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
@@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
/* Alloc memory for sg translation */
- host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
+ host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
dev_err(host->dev, "%s: could not alloc DMA memory\n",
@@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
struct dw_mci_board *pdata;
struct device *dev = host->dev;
struct device_node *np = dev->of_node;
- struct dw_mci_drv_data *drv_data = host->drv_data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
int idx, ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret);
}
+ if (of_find_property(np, "keep-power-in-suspend", NULL))
+ pdata->pm_caps |= MMC_PM_KEEP_POWER;
+
+ if (of_find_property(np, "enable-sdio-wakeup", NULL))
+ pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
return pdata;
}
@@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
int dw_mci_probe(struct dw_mci *host)
{
- struct dw_mci_drv_data *drv_data = host->drv_data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
int width, i, ret = 0;
u32 fifo_size;
int init_slots = 0;
@@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)
return -ENODEV;
}
- host->biu_clk = clk_get(host->dev, "biu");
+ host->biu_clk = devm_clk_get(host->dev, "biu");
if (IS_ERR(host->biu_clk)) {
dev_dbg(host->dev, "biu clock not available\n");
} else {
ret = clk_prepare_enable(host->biu_clk);
if (ret) {
dev_err(host->dev, "failed to enable biu clock\n");
- clk_put(host->biu_clk);
return ret;
}
}
- host->ciu_clk = clk_get(host->dev, "ciu");
+ host->ciu_clk = devm_clk_get(host->dev, "ciu");
if (IS_ERR(host->ciu_clk)) {
dev_dbg(host->dev, "ciu clock not available\n");
} else {
ret = clk_prepare_enable(host->ciu_clk);
if (ret) {
dev_err(host->dev, "failed to enable ciu clock\n");
- clk_put(host->ciu_clk);
goto err_clk_biu;
}
}
@@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->card_workqueue)
goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
- ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
+ ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
+ host->irq_flags, "dw-mci", host);
if (ret)
goto err_workqueue;
@@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)
} else {
dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_slots);
- goto err_init_slot;
+ goto err_workqueue;
}
/*
@@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host)
return 0;
-err_init_slot:
- free_irq(host->irq, host);
-
err_workqueue:
destroy_workqueue(host->card_workqueue);
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- dma_free_coherent(host->dev, PAGE_SIZE,
- host->sg_cpu, host->sg_dma);
- if (host->vmmc) {
+ if (host->vmmc)
regulator_disable(host->vmmc);
- regulator_put(host->vmmc);
- }
err_clk_ciu:
- if (!IS_ERR(host->ciu_clk)) {
+ if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
- clk_put(host->ciu_clk);
- }
+
err_clk_biu:
- if (!IS_ERR(host->biu_clk)) {
+ if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
- clk_put(host->biu_clk);
- }
+
return ret;
}
EXPORT_SYMBOL(dw_mci_probe);
@@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
- free_irq(host->irq, host);
destroy_workqueue(host->card_workqueue);
- dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
- if (host->vmmc) {
+ if (host->vmmc)
regulator_disable(host->vmmc);
- regulator_put(host->vmmc);
- }
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
+
if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
- clk_put(host->ciu_clk);
- clk_put(host->biu_clk);
}
EXPORT_SYMBOL(dw_mci_remove);
@@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
continue;
+ if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+ dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+ dw_mci_setup_bus(slot, true);
+ }
+
ret = mmc_resume_host(host->slot[i]->mmc);
if (ret < 0)
return ret;
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 6290b7f1ccfe..29e680f193a0 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
return 0;
for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->offset & 3 || sg->length & 3) {
+ if (sg->offset & 3 || sg->length & 3 || sg->length < 512) {
host->do_dma = 0;
return 0;
}
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 80d1e6d4b0ae..206fe499ded5 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -43,7 +43,6 @@
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/stmp_device.h>
-#include <linux/mmc/mxs-mmc.h>
#include <linux/spi/mxs-spi.h>
#define DRIVER_NAME "mxs-mmc"
@@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct mxs_mmc_host *host;
struct mmc_host *mmc;
struct resource *iores, *dmares;
- struct mxs_mmc_platform_data *pdata;
struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask;
struct regulator *reg_vmmc;
enum of_gpio_flags flags;
struct mxs_ssp *ssp;
+ u32 bus_width = 0;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
- pdata = mmc_dev(host->mmc)->platform_data;
- if (!pdata) {
- u32 bus_width = 0;
- of_property_read_u32(np, "bus-width", &bus_width);
- if (bus_width == 4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- else if (bus_width == 8)
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
- host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0,
- &flags);
- if (flags & OF_GPIO_ACTIVE_LOW)
- host->wp_inverted = 1;
- } else {
- if (pdata->flags & SLOTF_8_BIT_CAPABLE)
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
- if (pdata->flags & SLOTF_4_BIT_CAPABLE)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- host->wp_gpio = pdata->wp_gpio;
- }
+ of_property_read_u32(np, "bus-width", &bus_width);
+ if (bus_width == 4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+ else if (bus_width == 8)
+ mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+ host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+
+ if (flags & OF_GPIO_ACTIVE_LOW)
+ host->wp_inverted = 1;
mmc->f_min = 400000;
mmc->f_max = 288000000;
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index fedd258cc4ea..d0a912fbad3b 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -37,6 +37,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <mach/hardware.h>
#include <plat/mmc.h>
@@ -62,6 +63,7 @@
#define VS18 (1 << 26)
#define VS30 (1 << 25)
+#define HSS (1 << 21)
#define SDVS18 (0x5 << 9)
#define SDVS30 (0x6 << 9)
#define SDVS33 (0x7 << 9)
@@ -78,28 +80,17 @@
#define CLKD_SHIFT 6
#define DTO_MASK 0x000F0000
#define DTO_SHIFT 16
-#define INT_EN_MASK 0x307F0033
-#define BWR_ENABLE (1 << 4)
-#define BRR_ENABLE (1 << 5)
-#define DTO_ENABLE (1 << 20)
#define INIT_STREAM (1 << 1)
#define DP_SELECT (1 << 21)
#define DDIR (1 << 4)
-#define DMA_EN 0x1
+#define DMAE 0x1
#define MSBS (1 << 5)
#define BCE (1 << 1)
#define FOUR_BIT (1 << 1)
+#define HSPE (1 << 2)
#define DDR (1 << 19)
#define DW8 (1 << 5)
-#define CC 0x1
-#define TC 0x02
#define OD 0x1
-#define ERR (1 << 15)
-#define CMD_TIMEOUT (1 << 16)
-#define DATA_TIMEOUT (1 << 20)
-#define CMD_CRC (1 << 17)
-#define DATA_CRC (1 << 21)
-#define CARD_ERR (1 << 28)
#define STAT_CLEAR 0xFFFFFFFF
#define INIT_STREAM_CMD 0x00000000
#define DUAL_VOLT_OCR_BIT 7
@@ -108,6 +99,26 @@
#define SOFTRESET (1 << 1)
#define RESETDONE (1 << 0)
+/* Interrupt masks for IE and ISE register */
+#define CC_EN (1 << 0)
+#define TC_EN (1 << 1)
+#define BWR_EN (1 << 4)
+#define BRR_EN (1 << 5)
+#define ERR_EN (1 << 15)
+#define CTO_EN (1 << 16)
+#define CCRC_EN (1 << 17)
+#define CEB_EN (1 << 18)
+#define CIE_EN (1 << 19)
+#define DTO_EN (1 << 20)
+#define DCRC_EN (1 << 21)
+#define DEB_EN (1 << 22)
+#define CERR_EN (1 << 28)
+#define BADA_EN (1 << 29)
+
+#define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\
+ DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
+ BRR_EN | BWR_EN | TC_EN | CC_EN)
+
#define MMC_AUTOSUSPEND_DELAY 100
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MIN_CLOCK 400000
@@ -302,7 +313,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
reg = regulator_get(host->dev, "vmmc");
if (IS_ERR(reg)) {
- dev_dbg(host->dev, "vmmc regulator missing\n");
+ dev_err(host->dev, "vmmc regulator missing\n");
return PTR_ERR(reg);
} else {
mmc_slot(host).set_power = omap_hsmmc_set_power;
@@ -455,13 +466,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
unsigned int irq_mask;
if (host->use_dma)
- irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
+ irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
else
irq_mask = INT_EN_MASK;
/* Disable timeout for erases */
if (cmd->opcode == MMC_ERASE)
- irq_mask &= ~DTO_ENABLE;
+ irq_mask &= ~DTO_EN;
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -494,6 +505,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
struct mmc_ios *ios = &host->mmc->ios;
unsigned long regval;
unsigned long timeout;
+ unsigned long clkdiv;
dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
@@ -501,7 +513,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
regval = OMAP_HSMMC_READ(host->base, SYSCTL);
regval = regval & ~(CLKD_MASK | DTO_MASK);
- regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
+ clkdiv = calc_divisor(host, ios);
+ regval = regval | (clkdiv << 6) | (DTO << 16);
OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@@ -512,6 +525,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
&& time_before(jiffies, timeout))
cpu_relax();
+ /*
+ * Enable High-Speed Support
+ * Pre-Requisites
+ * - Controller should support High-Speed-Enable Bit
+ * - Controller should not be using DDR Mode
+ * - Controller should advertise that it supports High Speed
+ * in capabilities register
+ * - MMC/SD clock coming out of controller > 25MHz
+ */
+ if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
+ (ios->timing != MMC_TIMING_UHS_DDR50) &&
+ ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
+ regval = OMAP_HSMMC_READ(host->base, HCTL);
+ if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
+ regval |= HSPE;
+ else
+ regval &= ~HSPE;
+
+ OMAP_HSMMC_WRITE(host->base, HCTL, regval);
+ }
+
omap_hsmmc_start_clock(host);
}
@@ -676,8 +710,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)
OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((reg != CC) && time_before(jiffies, timeout))
- reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
+ while ((reg != CC_EN) && time_before(jiffies, timeout))
+ reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
@@ -768,7 +802,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
}
if (host->use_dma)
- cmdreg |= DMA_EN;
+ cmdreg |= DMAE;
host->req_in_progress = 1;
@@ -968,16 +1002,20 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
__func__);
}
-static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err)
+static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
+ int err, int end_cmd)
{
- omap_hsmmc_reset_controller_fsm(host, SRC);
- host->cmd->error = err;
+ if (end_cmd) {
+ omap_hsmmc_reset_controller_fsm(host, SRC);
+ if (host->cmd)
+ host->cmd->error = err;
+ }
if (host->data) {
omap_hsmmc_reset_controller_fsm(host, SRD);
omap_hsmmc_dma_cleanup(host, err);
- }
-
+ } else if (host->mrq && host->mrq->cmd)
+ host->mrq->cmd->error = err;
}
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
@@ -988,23 +1026,25 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
data = host->data;
dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
- if (status & ERR) {
+ if (status & ERR_EN) {
omap_hsmmc_dbg_report_irq(host, status);
- if (status & (CMD_TIMEOUT | DATA_TIMEOUT))
- hsmmc_command_incomplete(host, -ETIMEDOUT);
- else if (status & (CMD_CRC | DATA_CRC))
- hsmmc_command_incomplete(host, -EILSEQ);
- end_cmd = 1;
+ if (status & (CTO_EN | CCRC_EN))
+ end_cmd = 1;
+ if (status & (CTO_EN | DTO_EN))
+ hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
+ else if (status & (CCRC_EN | DCRC_EN))
+ hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
+
if (host->data || host->response_busy) {
- end_trans = 1;
+ end_trans = !end_cmd;
host->response_busy = 0;
}
}
- if (end_cmd || ((status & CC) && host->cmd))
+ if (end_cmd || ((status & CC_EN) && host->cmd))
omap_hsmmc_cmd_done(host, host->cmd);
- if ((end_trans || (status & TC)) && host->mrq)
+ if ((end_trans || (status & TC_EN)) && host->mrq)
omap_hsmmc_xfer_done(host, data);
}
@@ -1101,7 +1141,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
return 0;
err:
- dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
+ dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
return ret;
}
@@ -1360,7 +1400,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
if (host->use_dma) {
ret = omap_hsmmc_start_dma_transfer(host, req);
if (ret != 0) {
- dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
+ dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
return ret;
}
}
@@ -1678,7 +1718,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
{
struct omap_mmc_platform_data *pdata;
struct device_node *np = dev->of_node;
- u32 bus_width;
+ u32 bus_width, max_freq;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -1705,6 +1745,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,needs-special-reset", NULL))
pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+ if (!of_property_read_u32(np, "max-frequency", &max_freq))
+ pdata->max_freq = max_freq;
+
+ if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
+ pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
+
return pdata;
}
#else
@@ -1725,6 +1771,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
const struct of_device_id *match;
dma_cap_mask_t mask;
unsigned tx_req, rx_req;
+ struct pinctrl *pinctrl;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) {
@@ -1821,7 +1868,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
* MMC can still work without debounce clock.
*/
if (IS_ERR(host->dbclk)) {
- dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
host->dbclk = NULL;
} else if (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
@@ -1889,13 +1935,13 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
ret = request_irq(host->irq, omap_hsmmc_irq, 0,
mmc_hostname(mmc), host);
if (ret) {
- dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+ dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
goto err_irq;
}
if (pdata->init != NULL) {
if (pdata->init(&pdev->dev) != 0) {
- dev_dbg(mmc_dev(host->mmc),
+ dev_err(mmc_dev(host->mmc),
"Unable to configure MMC IRQs\n");
goto err_irq_cd_init;
}
@@ -1918,7 +1964,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host);
if (ret) {
- dev_dbg(mmc_dev(host->mmc),
+ dev_err(mmc_dev(host->mmc),
"Unable to grab MMC CD IRQ\n");
goto err_irq_cd;
}
@@ -1928,6 +1974,11 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_disable_irq(host);
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ dev_warn(&pdev->dev,
+ "pins are not configured from the driver\n");
+
omap_hsmmc_protect_card(host);
mmc_add_host(mmc);
@@ -2027,6 +2078,25 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
+static int omap_hsmmc_prepare(struct device *dev)
+{
+ struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+
+ if (host->pdata->suspend)
+ return host->pdata->suspend(dev, host->slot_id);
+
+ return 0;
+}
+
+static void omap_hsmmc_complete(struct device *dev)
+{
+ struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+
+ if (host->pdata->resume)
+ host->pdata->resume(dev, host->slot_id);
+
+}
+
static int omap_hsmmc_suspend(struct device *dev)
{
int ret = 0;
@@ -2040,23 +2110,10 @@ static int omap_hsmmc_suspend(struct device *dev)
pm_runtime_get_sync(host->dev);
host->suspended = 1;
- if (host->pdata->suspend) {
- ret = host->pdata->suspend(dev, host->slot_id);
- if (ret) {
- dev_dbg(dev, "Unable to handle MMC board"
- " level suspend\n");
- host->suspended = 0;
- return ret;
- }
- }
ret = mmc_suspend_host(host->mmc);
if (ret) {
host->suspended = 0;
- if (host->pdata->resume) {
- if (host->pdata->resume(dev, host->slot_id))
- dev_dbg(dev, "Unmask interrupt failed\n");
- }
goto err;
}
@@ -2093,12 +2150,6 @@ static int omap_hsmmc_resume(struct device *dev)
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host);
- if (host->pdata->resume) {
- ret = host->pdata->resume(dev, host->slot_id);
- if (ret)
- dev_dbg(dev, "Unmask interrupt failed\n");
- }
-
omap_hsmmc_protect_card(host);
/* Notify the core to resume the host */
@@ -2114,8 +2165,10 @@ static int omap_hsmmc_resume(struct device *dev)
}
#else
+#define omap_hsmmc_prepare NULL
+#define omap_hsmmc_complete NULL
#define omap_hsmmc_suspend NULL
-#define omap_hsmmc_resume NULL
+#define omap_hsmmc_resume NULL
#endif
static int omap_hsmmc_runtime_suspend(struct device *dev)
@@ -2143,6 +2196,8 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
.suspend = omap_hsmmc_suspend,
.resume = omap_hsmmc_resume,
+ .prepare = omap_hsmmc_prepare,
+ .complete = omap_hsmmc_complete,
.runtime_suspend = omap_hsmmc_runtime_suspend,
.runtime_resume = omap_hsmmc_runtime_resume,
};
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 8fd50a211037..e6214480bc98 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -19,20 +19,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/err.h>
-#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
-#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
#include <linux/mmc/host.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include "sdhci-pltfm.h"
struct sdhci_dove_priv {
struct clk *clk;
+ int gpio_cd;
};
+static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data)
+{
+ struct sdhci_host *host = data;
+
+ tasklet_schedule(&host->card_tasklet);
+ return IRQ_HANDLED;
+}
+
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{
u16 ret;
@@ -50,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_dove_priv *priv = pltfm_host->priv;
u32 ret;
+ ret = readl(host->ioaddr + reg);
+
switch (reg) {
case SDHCI_CAPABILITIES:
- ret = readl(host->ioaddr + reg);
/* Mask the support for 3.0V */
ret &= ~SDHCI_CAN_VDD_300;
break;
- default:
- ret = readl(host->ioaddr + reg);
+ case SDHCI_PRESENT_STATE:
+ if (gpio_is_valid(priv->gpio_cd)) {
+ if (gpio_get_value(priv->gpio_cd) == 0)
+ ret |= SDHCI_CARD_PRESENT;
+ else
+ ret &= ~SDHCI_CARD_PRESENT;
+ }
+ break;
}
return ret;
}
@@ -92,25 +111,70 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
return -ENOMEM;
}
- priv->clk = clk_get(&pdev->dev, NULL);
- if (!IS_ERR(priv->clk))
- clk_prepare_enable(priv->clk);
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
- ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
- if (ret)
- goto sdhci_dove_register_fail;
+ if (pdev->dev.of_node) {
+ priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
+ "cd-gpios", 0);
+ } else {
+ priv->gpio_cd = -EINVAL;
+ }
+
+ if (gpio_is_valid(priv->gpio_cd)) {
+ ret = gpio_request(priv->gpio_cd, "sdhci-cd");
+ if (ret) {
+ dev_err(&pdev->dev, "card detect gpio request failed: %d\n",
+ ret);
+ return ret;
+ }
+ gpio_direction_input(priv->gpio_cd);
+ }
+
+ host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata);
+ if (IS_ERR(host)) {
+ ret = PTR_ERR(host);
+ goto err_sdhci_pltfm_init;
+ }
- host = platform_get_drvdata(pdev);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+
+ sdhci_get_of_property(pdev);
+
+ ret = sdhci_add_host(host);
+ if (ret)
+ goto err_sdhci_add;
+
+ /*
+ * We must request the IRQ after sdhci_add_host(), as the tasklet only
+ * gets setup in sdhci_add_host() and we oops.
+ */
+ if (gpio_is_valid(priv->gpio_cd)) {
+ ret = request_irq(gpio_to_irq(priv->gpio_cd),
+ sdhci_dove_carddetect_irq,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ mmc_hostname(host->mmc), host);
+ if (ret) {
+ dev_err(&pdev->dev, "card detect irq request failed: %d\n",
+ ret);
+ goto err_request_irq;
+ }
+ }
+
return 0;
-sdhci_dove_register_fail:
- if (!IS_ERR(priv->clk)) {
+err_request_irq:
+ sdhci_remove_host(host, 0);
+err_sdhci_add:
+ if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
- }
+ sdhci_pltfm_free(pdev);
+err_sdhci_pltfm_init:
+ if (gpio_is_valid(priv->gpio_cd))
+ gpio_free(priv->gpio_cd);
return ret;
}
@@ -122,10 +186,14 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev);
- if (!IS_ERR(priv->clk)) {
- clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
+ if (gpio_is_valid(priv->gpio_cd)) {
+ free_irq(gpio_to_irq(priv->gpio_cd), host);
+ gpio_free(priv->gpio_cd);
}
+
+ if (!IS_ERR(priv->clk))
+ clk_disable_unprepare(priv->clk);
+
return 0;
}
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index effc2acfe778..1849461c39ee 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
- imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+ imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL);
if (!imx_data) {
err = -ENOMEM;
- goto err_imx_data;
+ goto free_sdhci;
}
if (of_id)
@@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx_data->clk_ipg)) {
err = PTR_ERR(imx_data->clk_ipg);
- goto err_clk_get;
+ goto free_sdhci;
}
imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(imx_data->clk_ahb)) {
err = PTR_ERR(imx_data->clk_ahb);
- goto err_clk_get;
+ goto free_sdhci;
}
imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(imx_data->clk_per)) {
err = PTR_ERR(imx_data->clk_per);
- goto err_clk_get;
+ goto free_sdhci;
}
pltfm_host->clk = imx_data->clk_per;
@@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
- goto pin_err;
+ goto disable_clk;
}
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n");
err = -EINVAL;
- goto no_board_data;
+ goto disable_clk;
}
imx_data->boarddata = *((struct esdhc_platform_data *)
host->mmc->parent->platform_data);
@@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
/* write_protect */
if (boarddata->wp_type == ESDHC_WP_GPIO) {
- err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+ err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio,
+ GPIOF_IN, "ESDHC_WP");
if (err) {
dev_warn(mmc_dev(host->mmc),
"no write-protect pin available!\n");
@@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
switch (boarddata->cd_type) {
case ESDHC_CD_GPIO:
- err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+ err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio,
+ GPIOF_IN, "ESDHC_CD");
if (err) {
dev_err(mmc_dev(host->mmc),
"no card-detect pin available!\n");
- goto no_card_detect_pin;
+ goto disable_clk;
}
- err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+ err = devm_request_irq(&pdev->dev,
+ gpio_to_irq(boarddata->cd_gpio), cd_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host);
if (err) {
dev_err(mmc_dev(host->mmc), "request irq error\n");
- goto no_card_detect_irq;
+ goto disable_clk;
}
/* fall through */
@@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
err = sdhci_add_host(host);
if (err)
- goto err_add_host;
+ goto disable_clk;
return 0;
-err_add_host:
- if (gpio_is_valid(boarddata->cd_gpio))
- free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-no_card_detect_irq:
- if (gpio_is_valid(boarddata->cd_gpio))
- gpio_free(boarddata->cd_gpio);
- if (gpio_is_valid(boarddata->wp_gpio))
- gpio_free(boarddata->wp_gpio);
-no_card_detect_pin:
-no_board_data:
-pin_err:
+disable_clk:
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
-err_clk_get:
- kfree(imx_data);
-err_imx_data:
+free_sdhci:
sdhci_pltfm_free(pdev);
return err;
}
@@ -604,25 +595,14 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
- if (gpio_is_valid(boarddata->wp_gpio))
- gpio_free(boarddata->wp_gpio);
-
- if (gpio_is_valid(boarddata->cd_gpio)) {
- free_irq(gpio_to_irq(boarddata->cd_gpio), host);
- gpio_free(boarddata->cd_gpio);
- }
-
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
- kfree(imx_data);
-
sdhci_pltfm_free(pdev);
return 0;
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 63d219f57cae..60de2eeb39b1 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -22,6 +22,7 @@
#include "sdhci-esdhc.h"
#define VENDOR_V_22 0x12
+#define VENDOR_V_23 0x13
static u32 esdhc_readl(struct sdhci_host *host, int reg)
{
u32 ret;
@@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
return ret;
}
+static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+{
+ /*
+ * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
+ * when SYSCTL[RSTD]) is set for some special operations.
+ * No any impact other operation.
+ */
+ if (reg == SDHCI_INT_ENABLE)
+ val |= SDHCI_INT_BLK_GAP;
+ sdhci_be32bs_writel(host, val, reg);
+}
+
static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
{
if (reg == SDHCI_BLOCK_SIZE) {
@@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_be32bs_writeb(host, val, reg);
}
+/*
+ * For Abort or Suspend after Stop at Block Gap, ignore the ADMA
+ * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
+ * and Block Gap Event(IRQSTAT[BGE]) are also set.
+ * For Continue, apply soft reset for data(SYSCTL[RSTD]);
+ * and re-issue the entire read transaction from beginning.
+ */
+static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
+{
+ u32 tmp;
+ bool applicable;
+ dma_addr_t dmastart;
+ dma_addr_t dmanow;
+
+ tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+ tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+
+ applicable = (intmask & SDHCI_INT_DATA_END) &&
+ (intmask & SDHCI_INT_BLK_GAP) &&
+ (tmp == VENDOR_V_23);
+ if (!applicable)
+ return;
+
+ host->data->error = 0;
+ dmastart = sg_dma_address(host->data->sg);
+ dmanow = dmastart + host->data->bytes_xfered;
+ /*
+ * Force update to the next DMA block boundary.
+ */
+ dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+ SDHCI_DEFAULT_BOUNDARY_SIZE;
+ host->data->bytes_xfered = dmanow - dmastart;
+ sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+}
+
static int esdhc_of_enable_dma(struct sdhci_host *host)
{
setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
@@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (vvn == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+
+ if (vvn > VENDOR_V_22)
+ host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
}
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl,
.read_w = esdhc_readw,
.read_b = esdhc_readb,
- .write_l = sdhci_be32bs_writel,
+ .write_l = esdhc_writel,
.write_w = esdhc_writew,
.write_b = esdhc_writeb,
.set_clock = esdhc_of_set_clock,
@@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.platform_suspend = esdhc_of_suspend,
.platform_resume = esdhc_of_resume,
#endif
+ .adma_workaround = esdhci_of_adma_workaround,
};
static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 04936f353ced..0777fad997ba 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
SDHCI_TIMEOUT_CLK_UNIT |
SDHCI_CAN_VDD_330 |
+ SDHCI_CAN_DO_HISPD |
SDHCI_CAN_DO_SDMA;
return 0;
}
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 27164457f861..d4283ef5917a 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+ if (of_get_property(np, "no-1-8-v", NULL))
+ host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
@@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev)
clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk);
+
+ if (of_find_property(np, "keep-power-in-suspend", NULL))
+ host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+
+ if (of_find_property(np, "enable-sdio-wakeup", NULL))
+ host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
}
#else
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index e918a2bb3af1..60829c92bcfd 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0;
}
+static u32 pxav3_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ return clk_get_rate(pltfm_host->clk);
+}
+
static struct sdhci_ops pxav3_sdhci_ops = {
.platform_reset_exit = pxav3_set_private_registers,
.set_uhs_signaling = pxav3_set_uhs_signaling,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
+ .get_max_clock = pxav3_get_max_clock,
};
#ifdef CONFIG_OF
@@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
- | SDHCI_QUIRK_32BIT_ADMA_SIZE;
+ | SDHCI_QUIRK_32BIT_ADMA_SIZE
+ | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
/* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
@@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
if (pdata->quirks)
host->quirks |= pdata->quirks;
+ if (pdata->quirks2)
+ host->quirks2 |= pdata->quirks2;
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
if (pdata->host_caps2)
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index a54dd5d7a5f9..82b7a7ad4217 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -24,6 +24,7 @@
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/mmc/host.h>
@@ -57,6 +58,7 @@ struct sdhci_s3c {
int ext_cd_irq;
int ext_cd_gpio;
int *gpios;
+ struct pinctrl *pctrl;
struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK];
@@ -373,18 +375,27 @@ static struct sdhci_ops sdhci_s3c_ops = {
static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
+#ifdef CONFIG_PM_RUNTIME
+ struct sdhci_s3c *sc = sdhci_priv(host);
+#endif
unsigned long flags;
if (host) {
spin_lock_irqsave(&host->lock, flags);
if (state) {
dev_dbg(&dev->dev, "card inserted.\n");
+#ifdef CONFIG_PM_RUNTIME
+ clk_prepare_enable(sc->clk_io);
+#endif
host->flags &= ~SDHCI_DEVICE_DEAD;
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
} else {
dev_dbg(&dev->dev, "card removed.\n");
host->flags |= SDHCI_DEVICE_DEAD;
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+#ifdef CONFIG_PM_RUNTIME
+ clk_disable_unprepare(sc->clk_io);
+#endif
}
tasklet_schedule(&host->card_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
@@ -406,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
struct s3c_sdhci_platdata *pdata = sc->pdata;
struct device *dev = &sc->pdev->dev;
- if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
+ if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
sc->ext_cd_gpio = pdata->ext_cd_gpio;
sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
if (sc->ext_cd_irq &&
@@ -449,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -ENOMEM;
/* get the card detection method */
- if (of_get_property(node, "broken-cd", 0)) {
+ if (of_get_property(node, "broken-cd", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_NONE;
goto setup_bus;
}
- if (of_get_property(node, "non-removable", 0)) {
+ if (of_get_property(node, "non-removable", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
goto setup_bus;
}
@@ -477,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -EINVAL;
}
- dev_info(dev, "assuming no card detect line available\n");
- pdata->cd_type = S3C_SDHCI_CD_NONE;
+ /* assuming internal card detect that will be configured by pinctrl */
+ pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
+ goto setup_bus;
found_cd:
if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
@@ -487,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
if (of_get_property(node, "cd-inverted", NULL))
pdata->ext_cd_gpio_invert = 1;
} else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
- ret = gpio_request(gpio, "sdhci-cd");
+ ret = devm_gpio_request(dev, gpio, "sdhci-cd");
if (ret) {
dev_err(dev, "card detect gpio request failed\n");
return -EINVAL;
@@ -496,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
}
setup_bus:
+ if (!IS_ERR(ourhost->pctrl))
+ return 0;
+
/* get the gpios for command, clock and data lines */
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
gpio = of_get_gpio(node, cnt);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]\n", cnt);
- goto err_free_dt_cd_gpio;
+ return -EINVAL;
}
ourhost->gpios[cnt] = gpio;
}
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
- ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio");
+ ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio");
if (ret) {
dev_err(dev, "gpio[%d] request failed\n", cnt);
- goto err_free_dt_gpios;
+ return -EINVAL;
}
}
return 0;
-
- err_free_dt_gpios:
- while (--cnt >= 0)
- gpio_free(ourhost->gpios[cnt]);
- err_free_dt_cd_gpio:
- if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
- gpio_free(ourhost->ext_cd_gpio);
- return -EINVAL;
}
#else
static int __devinit sdhci_s3c_parse_dt(struct device *dev,
@@ -579,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
- goto err_pdata;
+ goto err_pdata_io_clk;
}
+ sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
+
if (pdev->dev.of_node) {
ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
if (ret)
- goto err_pdata;
+ goto err_pdata_io_clk;
} else {
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
sc->ext_cd_gpio = -1; /* invalid gpio number */
@@ -603,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
if (IS_ERR(sc->clk_io)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(sc->clk_io);
- goto err_io_clk;
+ goto err_pdata_io_clk;
}
/* enable the local io clock and keep it running for the moment. */
@@ -766,13 +775,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
- err_io_clk:
- for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
- gpio_free(sc->gpios[ptr]);
- if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
- gpio_free(sc->ext_cd_gpio);
-
- err_pdata:
+ err_pdata_io_clk:
sdhci_free_host(host);
return ret;
@@ -791,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc);
- if (gpio_is_valid(sc->ext_cd_gpio))
- gpio_free(sc->ext_cd_gpio);
-
#ifdef CONFIG_PM_RUNTIME
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_prepare_enable(sc->clk_io);
@@ -814,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
- if (pdev->dev.of_node) {
- for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
- gpio_free(sc->gpios[ptr]);
- }
-
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 6be89c032deb..87a700944b7d 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev)
goto put_clk;
}
+ ret = clk_set_rate(sdhci->clk, 50000000);
+ if (ret)
+ dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
+ clk_get_rate(sdhci->clk));
+
if (np) {
sdhci->data = sdhci_probe_config_dt(pdev);
if (IS_ERR(sdhci->data)) {
@@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev)
ret = sdhci_suspend_host(host);
if (!ret)
- clk_disable_unprepare(sdhci->clk);
+ clk_disable(sdhci->clk);
return ret;
}
@@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev)
struct spear_sdhci *sdhci = dev_get_platdata(dev);
int ret;
- ret = clk_prepare_enable(sdhci->clk);
+ ret = clk_enable(sdhci->clk);
if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n");
return ret;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c7851c0aabce..6f0bfc0c8c9c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
if (host->vqmmc) {
- ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000);
+ ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);
if (ret) {
pr_warning("%s: Switching to 3.3V signalling voltage "
" failed\n", mmc_hostname(host->mmc));
@@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
*/
if (host->vqmmc)
ret = regulator_set_voltage(host->vqmmc,
- 1800000, 1800000);
+ 1700000, 1950000);
else
ret = 0;
@@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
sdhci_runtime_pm_put(host);
}
-static const struct mmc_host_ops sdhci_ops = {
- .request = sdhci_request,
- .set_ios = sdhci_set_ios,
- .get_ro = sdhci_get_ro,
- .hw_reset = sdhci_hw_reset,
- .enable_sdio_irq = sdhci_enable_sdio_irq,
- .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
- .execute_tuning = sdhci_execute_tuning,
- .enable_preset_value = sdhci_enable_preset_value,
-};
-
-/*****************************************************************************\
- * *
- * Tasklets *
- * *
-\*****************************************************************************/
-
-static void sdhci_tasklet_card(unsigned long param)
+static void sdhci_card_event(struct mmc_host *mmc)
{
- struct sdhci_host *host;
+ struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
- host = (struct sdhci_host*)param;
-
spin_lock_irqsave(&host->lock, flags);
/* Check host->mrq first in case we are runtime suspended */
@@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param)
}
spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static const struct mmc_host_ops sdhci_ops = {
+ .request = sdhci_request,
+ .set_ios = sdhci_set_ios,
+ .get_ro = sdhci_get_ro,
+ .hw_reset = sdhci_hw_reset,
+ .enable_sdio_irq = sdhci_enable_sdio_irq,
+ .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
+ .execute_tuning = sdhci_execute_tuning,
+ .enable_preset_value = sdhci_enable_preset_value,
+ .card_event = sdhci_card_event,
+};
+
+/*****************************************************************************\
+ * *
+ * Tasklets *
+ * *
+\*****************************************************************************/
+
+static void sdhci_tasklet_card(unsigned long param)
+{
+ struct sdhci_host *host = (struct sdhci_host*)param;
+
+ sdhci_card_event(host->mmc);
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
@@ -2282,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_show_adma_error(host);
host->data->error = -EIO;
+ if (host->ops->adma_workaround)
+ host->ops->adma_workaround(host, intmask);
}
if (host->data->error)
@@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc));
host->vqmmc = NULL;
}
- }
- else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
+ } else {
regulator_enable(host->vqmmc);
- else
+ if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
+ 1950000))
+ caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
+ SDHCI_SUPPORT_SDR50 |
+ SDHCI_SUPPORT_DDR50);
+ }
+
+ if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
@@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc));
host->vmmc = NULL;
}
- } else
- regulator_enable(host->vmmc);
+ }
#ifdef CONFIG_REGULATOR
if (host->vmmc) {
- ret = regulator_is_supported_voltage(host->vmmc, 3300000,
- 3300000);
+ ret = regulator_is_supported_voltage(host->vmmc, 2700000,
+ 3600000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
caps[0] &= ~SDHCI_CAN_VDD_330;
- ret = regulator_is_supported_voltage(host->vmmc, 3000000,
- 3000000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
caps[0] &= ~SDHCI_CAN_VDD_300;
- ret = regulator_is_supported_voltage(host->vmmc, 1800000,
- 1800000);
+ ret = regulator_is_supported_voltage(host->vmmc, 1700000,
+ 1950000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
caps[0] &= ~SDHCI_CAN_VDD_180;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 71a4a7ed46c5..a6d69b7bdea2 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -120,6 +120,7 @@
#define SDHCI_SIGNAL_ENABLE 0x38
#define SDHCI_INT_RESPONSE 0x00000001
#define SDHCI_INT_DATA_END 0x00000002
+#define SDHCI_INT_BLK_GAP 0x00000004
#define SDHCI_INT_DMA_END 0x00000008
#define SDHCI_INT_SPACE_AVAIL 0x00000010
#define SDHCI_INT_DATA_AVAIL 0x00000020
@@ -146,7 +147,8 @@
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
- SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
+ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
+ SDHCI_INT_BLK_GAP)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
#define SDHCI_ACMD12_ERR 0x3C
@@ -278,6 +280,7 @@ struct sdhci_ops {
void (*hw_reset)(struct sdhci_host *host);
void (*platform_suspend)(struct sdhci_host *host);
void (*platform_resume)(struct sdhci_host *host);
+ void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
};
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index d25bc97dc5c6..ae795233a1d6 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1104,7 +1104,6 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
{
struct sh_mmcif_host *host = dev_id;
struct mmc_request *mrq = host->mrq;
- struct mmc_data *data = mrq->data;
cancel_delayed_work_sync(&host->timeout_work);
@@ -1152,13 +1151,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
case MMCIF_WAIT_FOR_READ_END:
case MMCIF_WAIT_FOR_WRITE_END:
if (host->sd_error)
- data->error = sh_mmcif_error_manage(host);
+ mrq->data->error = sh_mmcif_error_manage(host);
break;
default:
BUG();
}
if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
+ struct mmc_data *data = mrq->data;
if (!mrq->cmd->error && data && !data->error)
data->bytes_xfered =
data->blocks * data->blksz;
@@ -1231,10 +1231,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
host->sd_error = true;
dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
}
- if (host->state == STATE_IDLE) {
- dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state);
- return IRQ_HANDLED;
- }
if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
if (!host->dma_active)
return IRQ_WAKE_THREAD;
@@ -1310,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
struct resource *res;
void __iomem *reg;
- char clk_name[8];
irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1);
@@ -1360,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
host->power = false;
- snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
- host->hclk = clk_get(&pdev->dev, clk_name);
+ host->hclk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->hclk)) {
ret = PTR_ERR(host->hclk);
- dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
+ dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget;
}
ret = sh_mmcif_clk_update(host);
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 0bdc146178db..d6ff8531fb35 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
struct tmio_mmc_data *mmc_data;
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
struct tmio_mmc_host *host;
- char clk_name[8];
int irq, ret, i = 0;
bool multiplexed_isr = true;
@@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
}
}
- snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
- priv->clk = clk_get(&pdev->dev, clk_name);
+ priv->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
ret = PTR_ERR(priv->clk);
+ dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget;
}
@@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
mmc_hostname(host->mmc), (unsigned long)
(platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
- mmc_data->hclk / 1000000);
+ host->mmc->f_max / 1000000);
return ret;
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index d5655a63eda4..cb9f361c03ab 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2362,6 +2362,7 @@ error4:
error1:
usb_free_urb(command_out_urb);
error0:
+ usb_put_dev(udev);
return retval;
}
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
new file mode 100644
index 000000000000..5ba4605e4f80
--- /dev/null
+++ b/drivers/mmc/host/wmt-sdmmc.c
@@ -0,0 +1,1029 @@
+/*
+ * WM8505/WM8650 SD/MMC Host Controller
+ *
+ * Copyright (C) 2010 Tony Prisk
+ * Copyright (C) 2008 WonderMedia Technologies, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include <asm/byteorder.h>
+
+
+#define DRIVER_NAME "wmt-sdhc"
+
+
+/* MMC/SD controller registers */
+#define SDMMC_CTLR 0x00
+#define SDMMC_CMD 0x01
+#define SDMMC_RSPTYPE 0x02
+#define SDMMC_ARG 0x04
+#define SDMMC_BUSMODE 0x08
+#define SDMMC_BLKLEN 0x0C
+#define SDMMC_BLKCNT 0x0E
+#define SDMMC_RSP 0x10
+#define SDMMC_CBCR 0x20
+#define SDMMC_INTMASK0 0x24
+#define SDMMC_INTMASK1 0x25
+#define SDMMC_STS0 0x28
+#define SDMMC_STS1 0x29
+#define SDMMC_STS2 0x2A
+#define SDMMC_STS3 0x2B
+#define SDMMC_RSPTIMEOUT 0x2C
+#define SDMMC_CLK 0x30 /* VT8500 only */
+#define SDMMC_EXTCTRL 0x34
+#define SDMMC_SBLKLEN 0x38
+#define SDMMC_DMATIMEOUT 0x3C
+
+
+/* SDMMC_CTLR bit fields */
+#define CTLR_CMD_START 0x01
+#define CTLR_CMD_WRITE 0x04
+#define CTLR_FIFO_RESET 0x08
+
+/* SDMMC_BUSMODE bit fields */
+#define BM_SPI_MODE 0x01
+#define BM_FOURBIT_MODE 0x02
+#define BM_EIGHTBIT_MODE 0x04
+#define BM_SD_OFF 0x10
+#define BM_SPI_CS 0x20
+#define BM_SD_POWER 0x40
+#define BM_SOFT_RESET 0x80
+#define BM_ONEBIT_MASK 0xFD
+
+/* SDMMC_BLKLEN bit fields */
+#define BLKL_CRCERR_ABORT 0x0800
+#define BLKL_CD_POL_HIGH 0x1000
+#define BLKL_GPI_CD 0x2000
+#define BLKL_DATA3_CD 0x4000
+#define BLKL_INT_ENABLE 0x8000
+
+/* SDMMC_INTMASK0 bit fields */
+#define INT0_MBLK_TRAN_DONE_INT_EN 0x10
+#define INT0_BLK_TRAN_DONE_INT_EN 0x20
+#define INT0_CD_INT_EN 0x40
+#define INT0_DI_INT_EN 0x80
+
+/* SDMMC_INTMASK1 bit fields */
+#define INT1_CMD_RES_TRAN_DONE_INT_EN 0x02
+#define INT1_CMD_RES_TOUT_INT_EN 0x04
+#define INT1_MBLK_AUTO_STOP_INT_EN 0x08
+#define INT1_DATA_TOUT_INT_EN 0x10
+#define INT1_RESCRC_ERR_INT_EN 0x20
+#define INT1_RCRC_ERR_INT_EN 0x40
+#define INT1_WCRC_ERR_INT_EN 0x80
+
+/* SDMMC_STS0 bit fields */
+#define STS0_WRITE_PROTECT 0x02
+#define STS0_CD_DATA3 0x04
+#define STS0_CD_GPI 0x08
+#define STS0_MBLK_DONE 0x10
+#define STS0_BLK_DONE 0x20
+#define STS0_CARD_DETECT 0x40
+#define STS0_DEVICE_INS 0x80
+
+/* SDMMC_STS1 bit fields */
+#define STS1_SDIO_INT 0x01
+#define STS1_CMDRSP_DONE 0x02
+#define STS1_RSP_TIMEOUT 0x04
+#define STS1_AUTOSTOP_DONE 0x08
+#define STS1_DATA_TIMEOUT 0x10
+#define STS1_RSP_CRC_ERR 0x20
+#define STS1_RCRC_ERR 0x40
+#define STS1_WCRC_ERR 0x80
+
+/* SDMMC_STS2 bit fields */
+#define STS2_CMD_RES_BUSY 0x10
+#define STS2_DATARSP_BUSY 0x20
+#define STS2_DIS_FORCECLK 0x80
+
+
+/* MMC/SD DMA Controller Registers */
+#define SDDMA_GCR 0x100
+#define SDDMA_IER 0x104
+#define SDDMA_ISR 0x108
+#define SDDMA_DESPR 0x10C
+#define SDDMA_RBR 0x110
+#define SDDMA_DAR 0x114
+#define SDDMA_BAR 0x118
+#define SDDMA_CPR 0x11C
+#define SDDMA_CCR 0x120
+
+
+/* SDDMA_GCR bit fields */
+#define DMA_GCR_DMA_EN 0x00000001
+#define DMA_GCR_SOFT_RESET 0x00000100
+
+/* SDDMA_IER bit fields */
+#define DMA_IER_INT_EN 0x00000001
+
+/* SDDMA_ISR bit fields */
+#define DMA_ISR_INT_STS 0x00000001
+
+/* SDDMA_RBR bit fields */
+#define DMA_RBR_FORMAT 0x40000000
+#define DMA_RBR_END 0x80000000
+
+/* SDDMA_CCR bit fields */
+#define DMA_CCR_RUN 0x00000080
+#define DMA_CCR_IF_TO_PERIPHERAL 0x00000000
+#define DMA_CCR_PERIPHERAL_TO_IF 0x00400000
+
+/* SDDMA_CCR event status */
+#define DMA_CCR_EVT_NO_STATUS 0x00000000
+#define DMA_CCR_EVT_UNDERRUN 0x00000001
+#define DMA_CCR_EVT_OVERRUN 0x00000002
+#define DMA_CCR_EVT_DESP_READ 0x00000003
+#define DMA_CCR_EVT_DATA_RW 0x00000004
+#define DMA_CCR_EVT_EARLY_END 0x00000005
+#define DMA_CCR_EVT_SUCCESS 0x0000000F
+
+#define PDMA_READ 0x00
+#define PDMA_WRITE 0x01
+
+#define WMT_SD_POWER_OFF 0
+#define WMT_SD_POWER_ON 1
+
+struct wmt_dma_descriptor {
+ u32 flags;
+ u32 data_buffer_addr;
+ u32 branch_addr;
+ u32 reserved1;
+};
+
+struct wmt_mci_caps {
+ unsigned int f_min;
+ unsigned int f_max;
+ u32 ocr_avail;
+ u32 caps;
+ u32 max_seg_size;
+ u32 max_segs;
+ u32 max_blk_size;
+};
+
+struct wmt_mci_priv {
+ struct mmc_host *mmc;
+ void __iomem *sdmmc_base;
+
+ int irq_regular;
+ int irq_dma;
+
+ void *dma_desc_buffer;
+ dma_addr_t dma_desc_device_addr;
+
+ struct completion cmdcomp;
+ struct completion datacomp;
+
+ struct completion *comp_cmd;
+ struct completion *comp_dma;
+
+ struct mmc_request *req;
+ struct mmc_command *cmd;
+
+ struct clk *clk_sdmmc;
+ struct device *dev;
+
+ u8 power_inverted;
+ u8 cd_inverted;
+};
+
+static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable)
+{
+ u32 reg_tmp;
+ if (enable) {
+ if (priv->power_inverted) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SD_OFF,
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ } else {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & (~BM_SD_OFF),
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ }
+ } else {
+ if (priv->power_inverted) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & (~BM_SD_OFF),
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ } else {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SD_OFF,
+ priv->sdmmc_base + SDMMC_BUSMODE);
+ }
+ }
+}
+
+static void wmt_mci_read_response(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv;
+ int idx1, idx2;
+ u8 tmp_resp;
+ u32 response;
+
+ priv = mmc_priv(mmc);
+
+ for (idx1 = 0; idx1 < 4; idx1++) {
+ response = 0;
+ for (idx2 = 0; idx2 < 4; idx2++) {
+ if ((idx1 == 3) && (idx2 == 3))
+ tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP);
+ else
+ tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP +
+ (idx1*4) + idx2 + 1);
+ response |= (tmp_resp << (idx2 * 8));
+ }
+ priv->cmd->resp[idx1] = cpu_to_be32(response);
+ }
+}
+
+static void wmt_mci_start_command(struct wmt_mci_priv *priv)
+{
+ u32 reg_tmp;
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR);
+}
+
+static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype,
+ u32 arg, u8 rsptype)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ /* write command, arg, resptype registers */
+ writeb(command, priv->sdmmc_base + SDMMC_CMD);
+ writel(arg, priv->sdmmc_base + SDMMC_ARG);
+ writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE);
+
+ /* reset response FIFO */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR);
+
+ /* ensure clock enabled - VT3465 */
+ wmt_set_sd_power(priv, WMT_SD_POWER_ON);
+
+ /* clear status bits */
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS2);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS3);
+
+ /* set command type */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb((reg_tmp & 0x0F) | (cmdtype << 4),
+ priv->sdmmc_base + SDMMC_CTLR);
+
+ return 0;
+}
+
+static void wmt_mci_disable_dma(struct wmt_mci_priv *priv)
+{
+ writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR);
+ writel(0, priv->sdmmc_base + SDDMA_IER);
+}
+
+static void wmt_complete_data_request(struct wmt_mci_priv *priv)
+{
+ struct mmc_request *req;
+ req = priv->req;
+
+ req->data->bytes_xfered = req->data->blksz * req->data->blocks;
+
+ /* unmap the DMA pages used for write data */
+ if (req->data->flags & MMC_DATA_WRITE)
+ dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg,
+ req->data->sg_len, DMA_TO_DEVICE);
+ else
+ dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg,
+ req->data->sg_len, DMA_FROM_DEVICE);
+
+ /* Check if the DMA ISR returned a data error */
+ if ((req->cmd->error) || (req->data->error))
+ mmc_request_done(priv->mmc, req);
+ else {
+ wmt_mci_read_response(priv->mmc);
+ if (!req->data->stop) {
+ /* single-block read/write requests end here */
+ mmc_request_done(priv->mmc, req);
+ } else {
+ /*
+ * we change the priv->cmd variable so the response is
+ * stored in the stop struct rather than the original
+ * calling command struct
+ */
+ priv->comp_cmd = &priv->cmdcomp;
+ init_completion(priv->comp_cmd);
+ priv->cmd = req->data->stop;
+ wmt_mci_send_command(priv->mmc, req->data->stop->opcode,
+ 7, req->data->stop->arg, 9);
+ wmt_mci_start_command(priv);
+ }
+ }
+}
+
+static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data)
+{
+ struct mmc_host *mmc;
+ struct wmt_mci_priv *priv;
+
+ int status;
+
+ priv = (struct wmt_mci_priv *)data;
+ mmc = priv->mmc;
+
+ status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F;
+
+ if (status != DMA_CCR_EVT_SUCCESS) {
+ dev_err(priv->dev, "DMA Error: Status = %d\n", status);
+ priv->req->data->error = -ETIMEDOUT;
+ complete(priv->comp_dma);
+ return IRQ_HANDLED;
+ }
+
+ priv->req->data->error = 0;
+
+ wmt_mci_disable_dma(priv);
+
+ complete(priv->comp_dma);
+
+ if (priv->comp_cmd) {
+ if (completion_done(priv->comp_cmd)) {
+ /*
+ * if the command (regular) interrupt has already
+ * completed, finish off the request otherwise we wait
+ * for the command interrupt and finish from there.
+ */
+ wmt_complete_data_request(priv);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data)
+{
+ struct wmt_mci_priv *priv;
+ u32 status0;
+ u32 status1;
+ u32 status2;
+ u32 reg_tmp;
+ int cmd_done;
+
+ priv = (struct wmt_mci_priv *)data;
+ cmd_done = 0;
+ status0 = readb(priv->sdmmc_base + SDMMC_STS0);
+ status1 = readb(priv->sdmmc_base + SDMMC_STS1);
+ status2 = readb(priv->sdmmc_base + SDMMC_STS2);
+
+ /* Check for card insertion */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0);
+ if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) {
+ mmc_detect_change(priv->mmc, 0);
+ if (priv->cmd)
+ priv->cmd->error = -ETIMEDOUT;
+ if (priv->comp_cmd)
+ complete(priv->comp_cmd);
+ if (priv->comp_dma) {
+ wmt_mci_disable_dma(priv);
+ complete(priv->comp_dma);
+ }
+ writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0);
+ return IRQ_HANDLED;
+ }
+
+ if ((!priv->req->data) ||
+ ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) {
+ /* handle non-data & stop_transmission requests */
+ if (status1 & STS1_CMDRSP_DONE) {
+ priv->cmd->error = 0;
+ cmd_done = 1;
+ } else if ((status1 & STS1_RSP_TIMEOUT) ||
+ (status1 & STS1_DATA_TIMEOUT)) {
+ priv->cmd->error = -ETIMEDOUT;
+ cmd_done = 1;
+ }
+
+ if (cmd_done) {
+ priv->comp_cmd = NULL;
+
+ if (!priv->cmd->error)
+ wmt_mci_read_response(priv->mmc);
+
+ priv->cmd = NULL;
+
+ mmc_request_done(priv->mmc, priv->req);
+ }
+ } else {
+ /* handle data requests */
+ if (status1 & STS1_CMDRSP_DONE) {
+ if (priv->cmd)
+ priv->cmd->error = 0;
+ if (priv->comp_cmd)
+ complete(priv->comp_cmd);
+ }
+
+ if ((status1 & STS1_RSP_TIMEOUT) ||
+ (status1 & STS1_DATA_TIMEOUT)) {
+ if (priv->cmd)
+ priv->cmd->error = -ETIMEDOUT;
+ if (priv->comp_cmd)
+ complete(priv->comp_cmd);
+ if (priv->comp_dma) {
+ wmt_mci_disable_dma(priv);
+ complete(priv->comp_dma);
+ }
+ }
+
+ if (priv->comp_dma) {
+ /*
+ * If the dma interrupt has already completed, finish
+ * off the request; otherwise we wait for the DMA
+ * interrupt and finish from there.
+ */
+ if (completion_done(priv->comp_dma))
+ wmt_complete_data_request(priv);
+ }
+ }
+
+ writeb(status0, priv->sdmmc_base + SDMMC_STS0);
+ writeb(status1, priv->sdmmc_base + SDMMC_STS1);
+ writeb(status2, priv->sdmmc_base + SDMMC_STS2);
+
+ return IRQ_HANDLED;
+}
+
+static void wmt_reset_hardware(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ /* reset controller */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE);
+
+ /* reset response FIFO */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+ writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR);
+
+ /* enable GPI pin to detect card */
+ writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN);
+
+ /* clear interrupt status */
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ /* setup interrupts */
+ writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base +
+ SDMMC_INTMASK0);
+ writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN |
+ INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1);
+
+ /* set the DMA timeout */
+ writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT);
+
+ /* auto clock freezing enable */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2);
+ writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2);
+
+ /* set a default clock speed of 400Khz */
+ clk_set_rate(priv->clk_sdmmc, 400000);
+}
+
+static int wmt_dma_init(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv;
+
+ priv = mmc_priv(mmc);
+
+ writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR);
+ writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR);
+ if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0)
+ return 0;
+ else
+ return 1;
+}
+
+static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc,
+ u16 req_count, u32 buffer_addr, u32 branch_addr, int end)
+{
+ desc->flags = 0x40000000 | req_count;
+ if (end)
+ desc->flags |= 0x80000000;
+ desc->data_buffer_addr = buffer_addr;
+ desc->branch_addr = branch_addr;
+}
+
+static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ /* Enable DMA Interrupts */
+ writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER);
+
+ /* Write DMA Descriptor Pointer Register */
+ writel(descaddr, priv->sdmmc_base + SDDMA_DESPR);
+
+ writel(0x00, priv->sdmmc_base + SDDMA_CCR);
+
+ if (dir == PDMA_WRITE) {
+ reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+ writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base +
+ SDDMA_CCR);
+ } else {
+ reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+ writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base +
+ SDDMA_CCR);
+ }
+}
+
+static void wmt_dma_start(struct wmt_mci_priv *priv)
+{
+ u32 reg_tmp;
+
+ reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+ writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR);
+}
+
+static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+ struct wmt_mci_priv *priv;
+ struct wmt_dma_descriptor *desc;
+ u8 command;
+ u8 cmdtype;
+ u32 arg;
+ u8 rsptype;
+ u32 reg_tmp;
+
+ struct scatterlist *sg;
+ int i;
+ int sg_cnt;
+ int offset;
+ u32 dma_address;
+ int desc_cnt;
+
+ priv = mmc_priv(mmc);
+ priv->req = req;
+
+ /*
+ * Use the cmd variable to pass a pointer to the resp[] structure
+ * This is required on multi-block requests to pass the pointer to the
+ * stop command
+ */
+ priv->cmd = req->cmd;
+
+ command = req->cmd->opcode;
+ arg = req->cmd->arg;
+ rsptype = mmc_resp_type(req->cmd);
+ cmdtype = 0;
+
+ /* rsptype=7 only valid for SPI commands - should be =2 for SD */
+ if (rsptype == 7)
+ rsptype = 2;
+ /* rsptype=21 is R1B, convert for controller */
+ if (rsptype == 21)
+ rsptype = 9;
+
+ if (!req->data) {
+ wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype);
+ wmt_mci_start_command(priv);
+ /* completion is now handled in the regular_isr() */
+ }
+ if (req->data) {
+ priv->comp_cmd = &priv->cmdcomp;
+ init_completion(priv->comp_cmd);
+
+ wmt_dma_init(mmc);
+
+ /* set controller data length */
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew((reg_tmp & 0xF800) | (req->data->blksz - 1),
+ priv->sdmmc_base + SDMMC_BLKLEN);
+
+ /* set controller block count */
+ writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT);
+
+ desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer;
+
+ if (req->data->flags & MMC_DATA_WRITE) {
+ sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg,
+ req->data->sg_len, DMA_TO_DEVICE);
+ cmdtype = 1;
+ if (req->data->blocks > 1)
+ cmdtype = 3;
+ } else {
+ sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg,
+ req->data->sg_len, DMA_FROM_DEVICE);
+ cmdtype = 2;
+ if (req->data->blocks > 1)
+ cmdtype = 4;
+ }
+
+ dma_address = priv->dma_desc_device_addr + 16;
+ desc_cnt = 0;
+
+ for_each_sg(req->data->sg, sg, sg_cnt, i) {
+ offset = 0;
+ while (offset < sg_dma_len(sg)) {
+ wmt_dma_init_descriptor(desc, req->data->blksz,
+ sg_dma_address(sg)+offset,
+ dma_address, 0);
+ desc++;
+ desc_cnt++;
+ offset += req->data->blksz;
+ dma_address += 16;
+ if (desc_cnt == req->data->blocks)
+ break;
+ }
+ }
+ desc--;
+ desc->flags |= 0x80000000;
+
+ if (req->data->flags & MMC_DATA_WRITE)
+ wmt_dma_config(mmc, priv->dma_desc_device_addr,
+ PDMA_WRITE);
+ else
+ wmt_dma_config(mmc, priv->dma_desc_device_addr,
+ PDMA_READ);
+
+ wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype);
+
+ priv->comp_dma = &priv->datacomp;
+ init_completion(priv->comp_dma);
+
+ wmt_dma_start(priv);
+ wmt_mci_start_command(priv);
+ }
+}
+
+static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct wmt_mci_priv *priv;
+ u32 reg_tmp;
+
+ priv = mmc_priv(mmc);
+
+ if (ios->power_mode == MMC_POWER_UP) {
+ wmt_reset_hardware(mmc);
+
+ wmt_set_sd_power(priv, WMT_SD_POWER_ON);
+ }
+ if (ios->power_mode == MMC_POWER_OFF)
+ wmt_set_sd_power(priv, WMT_SD_POWER_OFF);
+
+ if (ios->clock != 0)
+ clk_set_rate(priv->clk_sdmmc, ios->clock);
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_8:
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+ writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL);
+ break;
+ case MMC_BUS_WIDTH_4:
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+ writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL);
+ break;
+ case MMC_BUS_WIDTH_1:
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+ writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL);
+ break;
+ }
+}
+
+static int wmt_mci_get_ro(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv = mmc_priv(mmc);
+
+ return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT);
+}
+
+static int wmt_mci_get_cd(struct mmc_host *mmc)
+{
+ struct wmt_mci_priv *priv = mmc_priv(mmc);
+ u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3;
+
+ return !(cd ^ priv->cd_inverted);
+}
+
+static struct mmc_host_ops wmt_mci_ops = {
+ .request = wmt_mci_request,
+ .set_ios = wmt_mci_set_ios,
+ .get_ro = wmt_mci_get_ro,
+ .get_cd = wmt_mci_get_cd,
+};
+
+/* Controller capabilities */
+static struct wmt_mci_caps wm8505_caps = {
+ .f_min = 390425,
+ .f_max = 50000000,
+ .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |
+ MMC_CAP_SD_HIGHSPEED,
+ .max_seg_size = 65024,
+ .max_segs = 128,
+ .max_blk_size = 2048,
+};
+
+static struct of_device_id wmt_mci_dt_ids[] = {
+ { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps },
+ { /* Sentinel */ },
+};
+
+static int __devinit wmt_mci_probe(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct wmt_mci_priv *priv;
+ struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(wmt_mci_dt_ids, &pdev->dev);
+ const struct wmt_mci_caps *wmt_caps = of_id->data;
+ int ret;
+ int regular_irq, dma_irq;
+
+ if (!of_id || !of_id->data) {
+ dev_err(&pdev->dev, "Controller capabilities data missing\n");
+ return -EFAULT;
+ }
+
+ if (!np) {
+ dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
+ return -EFAULT;
+ }
+
+ regular_irq = irq_of_parse_and_map(np, 0);
+ dma_irq = irq_of_parse_and_map(np, 1);
+
+ if (!regular_irq || !dma_irq) {
+ dev_err(&pdev->dev, "Getting IRQs failed!\n");
+ ret = -ENXIO;
+ goto fail1;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev);
+ if (!mmc) {
+ dev_err(&pdev->dev, "Failed to allocate mmc_host\n");
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ mmc->ops = &wmt_mci_ops;
+ mmc->f_min = wmt_caps->f_min;
+ mmc->f_max = wmt_caps->f_max;
+ mmc->ocr_avail = wmt_caps->ocr_avail;
+ mmc->caps = wmt_caps->caps;
+
+ mmc->max_seg_size = wmt_caps->max_seg_size;
+ mmc->max_segs = wmt_caps->max_segs;
+ mmc->max_blk_size = wmt_caps->max_blk_size;
+
+ mmc->max_req_size = (16*512*mmc->max_segs);
+ mmc->max_blk_count = mmc->max_req_size / 512;
+
+ priv = mmc_priv(mmc);
+ priv->mmc = mmc;
+ priv->dev = &pdev->dev;
+
+ priv->power_inverted = 0;
+ priv->cd_inverted = 0;
+
+ if (of_get_property(np, "sdon-inverted", NULL))
+ priv->power_inverted = 1;
+ if (of_get_property(np, "cd-inverted", NULL))
+ priv->cd_inverted = 1;
+
+ priv->sdmmc_base = of_iomap(np, 0);
+ if (!priv->sdmmc_base) {
+ dev_err(&pdev->dev, "Failed to map IO space\n");
+ ret = -ENOMEM;
+ goto fail2;
+ }
+
+ priv->irq_regular = regular_irq;
+ priv->irq_dma = dma_irq;
+
+ ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Register regular IRQ fail\n");
+ goto fail3;
+ }
+
+ ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv);
+ if (ret) {
+ dev_err(&pdev->dev, "Register DMA IRQ fail\n");
+ goto fail4;
+ }
+
+ /* alloc some DMA buffers for descriptors/transfers */
+ priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev,
+ mmc->max_blk_count * 16,
+ &priv->dma_desc_device_addr,
+ 208);
+ if (!priv->dma_desc_buffer) {
+ dev_err(&pdev->dev, "DMA alloc fail\n");
+ ret = -EPERM;
+ goto fail5;
+ }
+
+ platform_set_drvdata(pdev, mmc);
+
+ priv->clk_sdmmc = of_clk_get(np, 0);
+ if (IS_ERR(priv->clk_sdmmc)) {
+ dev_err(&pdev->dev, "Error getting clock\n");
+ ret = PTR_ERR(priv->clk_sdmmc);
+ goto fail5;
+ }
+
+ clk_prepare_enable(priv->clk_sdmmc);
+
+ /* configure the controller to a known 'ready' state */
+ wmt_reset_hardware(mmc);
+
+ mmc_add_host(mmc);
+
+ dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
+
+ return 0;
+fail5:
+ free_irq(dma_irq, priv);
+fail4:
+ free_irq(regular_irq, priv);
+fail3:
+ iounmap(priv->sdmmc_base);
+fail2:
+ mmc_free_host(mmc);
+fail1:
+ return ret;
+}
+
+static int __devexit wmt_mci_remove(struct platform_device *pdev)
+{
+ struct mmc_host *mmc;
+ struct wmt_mci_priv *priv;
+ struct resource *res;
+ u32 reg_tmp;
+
+ mmc = platform_get_drvdata(pdev);
+ priv = mmc_priv(mmc);
+
+ /* reset SD controller */
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE);
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ /* release the dma buffers */
+ dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16,
+ priv->dma_desc_buffer, priv->dma_desc_device_addr);
+
+ mmc_remove_host(mmc);
+
+ free_irq(priv->irq_regular, priv);
+ free_irq(priv->irq_dma, priv);
+
+ iounmap(priv->sdmmc_base);
+
+ clk_disable_unprepare(priv->clk_sdmmc);
+ clk_put(priv->clk_sdmmc);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ mmc_free_host(mmc);
+
+ platform_set_drvdata(pdev, NULL);
+
+ dev_info(&pdev->dev, "WMT MCI device removed\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int wmt_mci_suspend(struct device *dev)
+{
+ u32 reg_tmp;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct wmt_mci_priv *priv;
+ int ret;
+
+ if (!mmc)
+ return 0;
+
+ priv = mmc_priv(mmc);
+ ret = mmc_suspend_host(mmc);
+
+ if (!ret) {
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN);
+
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+ writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+ clk_disable(priv->clk_sdmmc);
+ }
+ return ret;
+}
+
+static int wmt_mci_resume(struct device *dev)
+{
+ u32 reg_tmp;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct wmt_mci_priv *priv;
+ int ret = 0;
+
+ if (mmc) {
+ priv = mmc_priv(mmc);
+ clk_enable(priv->clk_sdmmc);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+ writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+ SDMMC_BUSMODE);
+
+ reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+ writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE),
+ priv->sdmmc_base + SDMMC_BLKLEN);
+
+ reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0);
+ writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base +
+ SDMMC_INTMASK0);
+
+ ret = mmc_resume_host(mmc);
+ }
+
+ return ret;
+}
+
+static const struct dev_pm_ops wmt_mci_pm = {
+ .suspend = wmt_mci_suspend,
+ .resume = wmt_mci_resume,
+};
+
+#define wmt_mci_pm_ops (&wmt_mci_pm)
+
+#else /* !CONFIG_PM */
+
+#define wmt_mci_pm_ops NULL
+
+#endif
+
+static struct platform_driver wmt_mci_driver = {
+ .probe = wmt_mci_probe,
+ .remove = __exit_p(wmt_mci_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = wmt_mci_pm_ops,
+ .of_match_table = wmt_mci_dt_ids,
+ },
+};
+
+module_platform_driver(wmt_mci_driver);
+
+MODULE_DESCRIPTION("Wondermedia MMC/SD Driver");
+MODULE_AUTHOR("Tony Prisk");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids);
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 8f52fc858e48..5a5cd2ace4a6 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -240,7 +240,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
if (*(szlength) != '+') {
devlength = simple_strtoul(szlength, &buffer, 0);
- devlength = handle_unit(devlength, buffer) - devstart;
+ devlength = handle_unit(devlength, buffer);
if (devlength < devstart)
goto err_out;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 374c46dff7dd..ec794a72975d 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1077,7 +1077,8 @@ EXPORT_SYMBOL_GPL(mtd_writev);
* until the request succeeds or until the allocation size falls below
* the system page size. This attempts to make sure it does not adversely
* impact system performance, so when allocating more than one page, we
- * ask the memory allocator to avoid re-trying.
+ * ask the memory allocator to avoid re-trying, swapping, writing back
+ * or performing I/O.
*
* Note, this function also makes sure that the allocated buffer is aligned to
* the MTD device's min. I/O unit, i.e. the "mtd->writesize" value.
@@ -1091,7 +1092,8 @@ EXPORT_SYMBOL_GPL(mtd_writev);
*/
void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size)
{
- gfp_t flags = __GFP_NOWARN | __GFP_WAIT | __GFP_NORETRY;
+ gfp_t flags = __GFP_NOWARN | __GFP_WAIT |
+ __GFP_NORETRY | __GFP_NO_KSWAPD;
size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE);
void *kbuf;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index 914455783302..92623ac2015a 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -41,6 +41,7 @@
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/platform_data/atmel.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/cpu.h>
@@ -1370,6 +1371,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
struct resource *mem;
struct mtd_part_parser_data ppdata = {};
int res;
+ struct pinctrl *pinctrl;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
@@ -1414,6 +1416,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ dev_err(host->dev, "Failed to request pinctrl\n");
+ res = PTR_ERR(pinctrl);
+ goto err_ecc_ioremap;
+ }
+
if (gpio_is_valid(host->board.rdy_pin)) {
res = gpio_request(host->board.rdy_pin, "nand_rdy");
if (res < 0) {
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index ec6841d8e956..1a03b7f673ce 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2983,13 +2983,15 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
/*
* Field definitions are in the following datasheets:
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
- * New style (6 byte ID): Samsung K9GAG08U0F (p.44)
+ * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
*
- * Check for ID length, cell type, and Hynix/Samsung ID to decide what
- * to do.
+ * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
+ * ID to decide what to do.
*/
- if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG) {
+ if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
+ (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ id_data[5] != 0x00) {
/* Calc pagesize */
mtd->writesize = 2048 << (extid & 0x03);
extid >>= 2;
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 64be8f0848b0..d9127e2ed808 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -121,7 +121,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
nr_parts = plen / sizeof(part[0]);
*pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL);
- if (!pparts)
+ if (!*pparts)
return -ENOMEM;
names = of_get_property(dp, "partition-names", &plen);
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 7153e0d27101..b3f41f200622 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -3694,7 +3694,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int
* flexonenand_set_boundary - Writes the SLC boundary
* @param mtd - mtd info structure
*/
-int flexonenand_set_boundary(struct mtd_info *mtd, int die,
+static int flexonenand_set_boundary(struct mtd_info *mtd, int die,
int boundary, int lock)
{
struct onenand_chip *this = mtd->priv;
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index da7b44998b40..2144f611196e 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -498,7 +498,7 @@ out:
* @ubi: UBI device description object
*
* This function returns a physical eraseblock in case of success and a
- * negative error code in case of failure. Might sleep.
+ * negative error code in case of failure.
*/
static int __wl_get_peb(struct ubi_device *ubi)
{
@@ -540,13 +540,6 @@ retry:
* ubi_wl_get_peb() after removing e from the pool. */
prot_queue_add(ubi, e);
#endif
- err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
- ubi->peb_size - ubi->vid_hdr_aloffset);
- if (err) {
- ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
- return err;
- }
-
return e->pnum;
}
@@ -679,17 +672,30 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
#else
static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi)
{
- return find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+ struct ubi_wl_entry *e;
+
+ e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF);
+ self_check_in_wl_tree(ubi, e, &ubi->free);
+ rb_erase(&e->u.rb, &ubi->free);
+
+ return e;
}
int ubi_wl_get_peb(struct ubi_device *ubi)
{
- int peb;
+ int peb, err;
spin_lock(&ubi->wl_lock);
peb = __wl_get_peb(ubi);
spin_unlock(&ubi->wl_lock);
+ err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset,
+ ubi->peb_size - ubi->vid_hdr_aloffset);
+ if (err) {
+ ubi_err("new PEB %d does not contain all 0xFF bytes", peb);
+ return err;
+ }
+
return peb;
}
#endif
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b2530b002125..a7d47350ea4b 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1379,6 +1379,8 @@ static void bond_compute_features(struct bonding *bond)
struct net_device *bond_dev = bond->dev;
netdev_features_t vlan_features = BOND_VLAN_FEATURES;
unsigned short max_hard_header_len = ETH_HLEN;
+ unsigned int gso_max_size = GSO_MAX_SIZE;
+ u16 gso_max_segs = GSO_MAX_SEGS;
int i;
unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE;
@@ -1394,11 +1396,16 @@ static void bond_compute_features(struct bonding *bond)
dst_release_flag &= slave->dev->priv_flags;
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
+
+ gso_max_size = min(gso_max_size, slave->dev->gso_max_size);
+ gso_max_segs = min(gso_max_segs, slave->dev->gso_max_segs);
}
done:
bond_dev->vlan_features = vlan_features;
bond_dev->hard_header_len = max_hard_header_len;
+ bond_dev->gso_max_segs = gso_max_segs;
+ netif_set_gso_max_size(bond_dev, gso_max_size);
flags = bond_dev->priv_flags & ~IFF_XMIT_DST_RELEASE;
bond_dev->priv_flags = flags | dst_release_flag;
@@ -3452,6 +3459,28 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count)
/*-------------------------- Device entry points ----------------------------*/
+static void bond_work_init_all(struct bonding *bond)
+{
+ INIT_DELAYED_WORK(&bond->mcast_work,
+ bond_resend_igmp_join_requests_delayed);
+ INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
+ INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ INIT_DELAYED_WORK(&bond->arp_work, bond_activebackup_arp_mon);
+ else
+ INIT_DELAYED_WORK(&bond->arp_work, bond_loadbalance_arp_mon);
+ INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
+}
+
+static void bond_work_cancel_all(struct bonding *bond)
+{
+ cancel_delayed_work_sync(&bond->mii_work);
+ cancel_delayed_work_sync(&bond->arp_work);
+ cancel_delayed_work_sync(&bond->alb_work);
+ cancel_delayed_work_sync(&bond->ad_work);
+ cancel_delayed_work_sync(&bond->mcast_work);
+}
+
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
@@ -3474,41 +3503,27 @@ static int bond_open(struct net_device *bond_dev)
}
read_unlock(&bond->lock);
- INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
+ bond_work_init_all(bond);
if (bond_is_lb(bond)) {
/* bond_alb_initialize must be called before the timer
* is started.
*/
- if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) {
- /* something went wrong - fail the open operation */
+ if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB)))
return -ENOMEM;
- }
-
- INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
queue_delayed_work(bond->wq, &bond->alb_work, 0);
}
- if (bond->params.miimon) { /* link check interval, in milliseconds. */
- INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
+ if (bond->params.miimon) /* link check interval, in milliseconds. */
queue_delayed_work(bond->wq, &bond->mii_work, 0);
- }
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_activebackup_arp_mon);
- else
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_loadbalance_arp_mon);
-
queue_delayed_work(bond->wq, &bond->arp_work, 0);
if (bond->params.arp_validate)
bond->recv_probe = bond_arp_rcv;
}
if (bond->params.mode == BOND_MODE_8023AD) {
- INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
bond->recv_probe = bond_3ad_lacpdu_recv;
@@ -3523,34 +3538,10 @@ static int bond_close(struct net_device *bond_dev)
struct bonding *bond = netdev_priv(bond_dev);
write_lock_bh(&bond->lock);
-
bond->send_peer_notif = 0;
-
write_unlock_bh(&bond->lock);
- if (bond->params.miimon) { /* link check interval, in milliseconds. */
- cancel_delayed_work_sync(&bond->mii_work);
- }
-
- if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- cancel_delayed_work_sync(&bond->arp_work);
- }
-
- switch (bond->params.mode) {
- case BOND_MODE_8023AD:
- cancel_delayed_work_sync(&bond->ad_work);
- break;
- case BOND_MODE_TLB:
- case BOND_MODE_ALB:
- cancel_delayed_work_sync(&bond->alb_work);
- break;
- default:
- break;
- }
-
- if (delayed_work_pending(&bond->mcast_work))
- cancel_delayed_work_sync(&bond->mcast_work);
-
+ bond_work_cancel_all(bond);
if (bond_is_lb(bond)) {
/* Must be called only after all
* slaves have been released
@@ -4429,26 +4420,6 @@ static void bond_setup(struct net_device *bond_dev)
bond_dev->features |= bond_dev->hw_features;
}
-static void bond_work_cancel_all(struct bonding *bond)
-{
- if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
- cancel_delayed_work_sync(&bond->mii_work);
-
- if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
- cancel_delayed_work_sync(&bond->arp_work);
-
- if (bond->params.mode == BOND_MODE_ALB &&
- delayed_work_pending(&bond->alb_work))
- cancel_delayed_work_sync(&bond->alb_work);
-
- if (bond->params.mode == BOND_MODE_8023AD &&
- delayed_work_pending(&bond->ad_work))
- cancel_delayed_work_sync(&bond->ad_work);
-
- if (delayed_work_pending(&bond->mcast_work))
- cancel_delayed_work_sync(&bond->mcast_work);
-}
-
/*
* Destroy a bonding device.
* Must be under rtnl_lock when this function is called.
@@ -4699,12 +4670,13 @@ static int bond_check_params(struct bond_params *params)
arp_ip_count++) {
/* not complete check, but should be good enough to
catch mistakes */
- if (!isdigit(arp_ip_target[arp_ip_count][0])) {
+ __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
+ if (!isdigit(arp_ip_target[arp_ip_count][0]) ||
+ ip == 0 || ip == htonl(INADDR_BROADCAST)) {
pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n",
arp_ip_target[arp_ip_count]);
arp_interval = 0;
} else {
- __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
arp_target[arp_ip_count] = ip;
}
}
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index ef8d2a080d17..1877ed7ca086 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -513,6 +513,8 @@ static ssize_t bonding_store_arp_interval(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
+ if (!rtnl_trylock())
+ return restart_syscall();
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no arp_interval value specified.\n",
bond->dev->name);
@@ -539,10 +541,6 @@ static ssize_t bonding_store_arp_interval(struct device *d,
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 (delayed_work_pending(&bond->mii_work)) {
- cancel_delayed_work(&bond->mii_work);
- flush_workqueue(bond->wq);
- }
}
if (!bond->params.arp_targets[0]) {
pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
@@ -554,19 +552,12 @@ static ssize_t bonding_store_arp_interval(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- if (!delayed_work_pending(&bond->arp_work)) {
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_activebackup_arp_mon);
- else
- INIT_DELAYED_WORK(&bond->arp_work,
- bond_loadbalance_arp_mon);
-
- queue_delayed_work(bond->wq, &bond->arp_work, 0);
- }
+ cancel_delayed_work_sync(&bond->mii_work);
+ queue_delayed_work(bond->wq, &bond->arp_work, 0);
}
out:
+ rtnl_unlock();
return ret;
}
static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR,
@@ -962,6 +953,8 @@ static ssize_t bonding_store_miimon(struct device *d,
int new_value, ret = count;
struct bonding *bond = to_bond(d);
+ if (!rtnl_trylock())
+ return restart_syscall();
if (sscanf(buf, "%d", &new_value) != 1) {
pr_err("%s: no miimon value specified.\n",
bond->dev->name);
@@ -993,10 +986,6 @@ static ssize_t bonding_store_miimon(struct device *d,
bond->params.arp_validate =
BOND_ARP_VALIDATE_NONE;
}
- if (delayed_work_pending(&bond->arp_work)) {
- cancel_delayed_work(&bond->arp_work);
- flush_workqueue(bond->wq);
- }
}
if (bond->dev->flags & IFF_UP) {
@@ -1005,15 +994,12 @@ static ssize_t bonding_store_miimon(struct device *d,
* timer will get fired off when the open function
* is called.
*/
- if (!delayed_work_pending(&bond->mii_work)) {
- INIT_DELAYED_WORK(&bond->mii_work,
- bond_mii_monitor);
- queue_delayed_work(bond->wq,
- &bond->mii_work, 0);
- }
+ cancel_delayed_work_sync(&bond->arp_work);
+ queue_delayed_work(bond->wq, &bond->mii_work, 0);
}
}
out:
+ rtnl_unlock();
return ret;
}
static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR,
@@ -1582,6 +1568,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
goto out;
}
+ read_lock(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (!bond_is_active_slave(slave)) {
if (new_value)
@@ -1590,6 +1577,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
slave->inactive = 1;
}
}
+ read_unlock(&bond->lock);
out:
return ret;
}
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 86f26a1ede4c..25723d8ee201 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
mc->pdev->dev.can.state = new_state;
if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
+ struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
+
peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts->hwtstamp = timeval_to_ktime(tv);
}
netif_rx(skb);
@@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
struct sk_buff *skb;
struct can_frame *cf;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
skb = alloc_can_skb(mc->netdev, &cf);
if (!skb)
@@ -652,7 +655,8 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
/* convert timestamp into kernel time */
peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
/* push the skb */
netif_rx(skb);
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index e1626d92511a..30d79bfa5b10 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -532,6 +532,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
struct can_frame *can_frame;
struct sk_buff *skb;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
skb = alloc_can_skb(netdev, &can_frame);
if (!skb)
@@ -549,7 +550,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
memcpy(can_frame->data, rx->data, can_frame->can_dlc);
peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
@@ -570,6 +572,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
u8 err_mask = 0;
struct sk_buff *skb;
struct timeval tv;
+ struct skb_shared_hwtstamps *hwts;
/* nothing should be sent while in BUS_OFF state */
if (dev->can.state == CAN_STATE_BUS_OFF)
@@ -664,7 +667,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
dev->can.state = new_state;
peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv);
- skb->tstamp = timeval_to_ktime(tv);
+ hwts = skb_hwtstamps(skb);
+ hwts->hwtstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += can_frame->can_dlc;
diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c
index d04911d33b64..47618e505355 100644
--- a/drivers/net/ethernet/8390/ne.c
+++ b/drivers/net/ethernet/8390/ne.c
@@ -813,6 +813,7 @@ static int __init ne_drv_probe(struct platform_device *pdev)
dev->irq = irq[this_dev];
dev->mem_end = bad[this_dev];
}
+ SET_NETDEV_DEV(dev, &pdev->dev);
err = do_ne_probe(dev);
if (err) {
free_netdev(dev);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index bd1fd3d87c24..01611b33a93d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9545,10 +9545,13 @@ static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp)
*/
static void __devinit bnx2x_prev_interrupted_dmae(struct bnx2x *bp)
{
- u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
- if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
- BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing");
- REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, 1 << BP_FUNC(bp));
+ if (!CHIP_IS_E1x(bp)) {
+ u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS);
+ if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) {
+ BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing");
+ REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR,
+ 1 << BP_FUNC(bp));
+ }
}
}
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 92317e9c0f73..60ac46f4ac08 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1860,10 +1860,14 @@ jme_open(struct net_device *netdev)
jme_clear_pm(jme);
JME_NAPI_ENABLE(jme);
- tasklet_enable(&jme->linkch_task);
- tasklet_enable(&jme->txclean_task);
- tasklet_hi_enable(&jme->rxclean_task);
- tasklet_hi_enable(&jme->rxempty_task);
+ tasklet_init(&jme->linkch_task, jme_link_change_tasklet,
+ (unsigned long) jme);
+ tasklet_init(&jme->txclean_task, jme_tx_clean_tasklet,
+ (unsigned long) jme);
+ tasklet_init(&jme->rxclean_task, jme_rx_clean_tasklet,
+ (unsigned long) jme);
+ tasklet_init(&jme->rxempty_task, jme_rx_empty_tasklet,
+ (unsigned long) jme);
rc = jme_request_irq(jme);
if (rc)
@@ -3079,22 +3083,6 @@ jme_init_one(struct pci_dev *pdev,
tasklet_init(&jme->pcc_task,
jme_pcc_tasklet,
(unsigned long) jme);
- tasklet_init(&jme->linkch_task,
- jme_link_change_tasklet,
- (unsigned long) jme);
- tasklet_init(&jme->txclean_task,
- jme_tx_clean_tasklet,
- (unsigned long) jme);
- tasklet_init(&jme->rxclean_task,
- jme_rx_clean_tasklet,
- (unsigned long) jme);
- tasklet_init(&jme->rxempty_task,
- jme_rx_empty_tasklet,
- (unsigned long) jme);
- tasklet_disable_nosync(&jme->linkch_task);
- tasklet_disable_nosync(&jme->txclean_task);
- tasklet_disable_nosync(&jme->rxclean_task);
- tasklet_disable_nosync(&jme->rxempty_task);
jme->dpi.cur = PCC_P1;
jme->reg_ghc = 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index 5d36795877cb..b799ab12a291 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -237,7 +237,7 @@ static int mlx4_en_dcbnl_ieee_setmaxrate(struct net_device *dev,
if (err)
return err;
- memcpy(priv->maxrate, tmp, sizeof(*priv->maxrate));
+ memcpy(priv->maxrate, tmp, sizeof(priv->maxrate));
return 0;
}
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index e558edd1cb6c..69e01977a1dd 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -5459,8 +5459,10 @@ static int prepare_hardware(struct net_device *dev)
rc = request_irq(dev->irq, netdev_intr, IRQF_SHARED, dev->name, dev);
if (rc)
return rc;
- tasklet_enable(&hw_priv->rx_tasklet);
- tasklet_enable(&hw_priv->tx_tasklet);
+ tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
+ (unsigned long) hw_priv);
+ tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
+ (unsigned long) hw_priv);
hw->promiscuous = 0;
hw->all_multi = 0;
@@ -7033,16 +7035,6 @@ static int __devinit pcidev_init(struct pci_dev *pdev,
spin_lock_init(&hw_priv->hwlock);
mutex_init(&hw_priv->lock);
- /* tasklet is enabled. */
- tasklet_init(&hw_priv->rx_tasklet, rx_proc_task,
- (unsigned long) hw_priv);
- tasklet_init(&hw_priv->tx_tasklet, tx_proc_task,
- (unsigned long) hw_priv);
-
- /* tasklet_enable will decrement the atomic counter. */
- tasklet_disable(&hw_priv->rx_tasklet);
- tasklet_disable(&hw_priv->tx_tasklet);
-
for (i = 0; i < TOTAL_PORT_NUM; i++)
init_waitqueue_head(&hw_priv->counter[i].counter);
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 1c818254b7be..609125a249d9 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -979,17 +979,6 @@ static void cp_init_hw (struct cp_private *cp)
cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
- cpw32_f(HiTxRingAddr, 0);
- cpw32_f(HiTxRingAddr + 4, 0);
-
- ring_dma = cp->ring_dma;
- cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
- cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
-
- ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
- cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
- cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
-
cp_start_hw(cp);
cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
@@ -1003,6 +992,17 @@ static void cp_init_hw (struct cp_private *cp)
cpw8(Config5, cpr8(Config5) & PMEStatus);
+ cpw32_f(HiTxRingAddr, 0);
+ cpw32_f(HiTxRingAddr + 4, 0);
+
+ ring_dma = cp->ring_dma;
+ cpw32_f(RxRingAddr, ring_dma & 0xffffffff);
+ cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16);
+
+ ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE;
+ cpw32_f(TxRingAddr, ring_dma & 0xffffffff);
+ cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16);
+
cpw16(MultiIntr, 0);
cpw8_f(Cfg9346, Cfg9346_Lock);
@@ -1060,17 +1060,22 @@ static int cp_init_rings (struct cp_private *cp)
static int cp_alloc_rings (struct cp_private *cp)
{
+ struct device *d = &cp->pdev->dev;
void *mem;
+ int rc;
- mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES,
- &cp->ring_dma, GFP_KERNEL);
+ mem = dma_alloc_coherent(d, CP_RING_BYTES, &cp->ring_dma, GFP_KERNEL);
if (!mem)
return -ENOMEM;
cp->rx_ring = mem;
cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
- return cp_init_rings(cp);
+ rc = cp_init_rings(cp);
+ if (rc < 0)
+ dma_free_coherent(d, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+
+ return rc;
}
static void cp_clean_rings (struct cp_private *cp)
diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c
index fb9f6b38511f..edf5edb13140 100644
--- a/drivers/net/ethernet/sis/sis900.c
+++ b/drivers/net/ethernet/sis/sis900.c
@@ -2479,7 +2479,7 @@ static int sis900_resume(struct pci_dev *pci_dev)
netif_start_queue(net_dev);
/* Workaround for EDB */
- sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
+ sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED);
/* Enable all known interrupts by setting the interrupt mask. */
sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE);
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index 62d1baf111ea..c53c0f4e2ce3 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -2110,7 +2110,7 @@ static void __devinit smsc911x_read_mac_address(struct net_device *dev)
static int __devinit smsc911x_init(struct net_device *dev)
{
struct smsc911x_data *pdata = netdev_priv(dev);
- unsigned int byte_test;
+ unsigned int byte_test, mask;
unsigned int to = 100;
SMSC_TRACE(pdata, probe, "Driver Parameters:");
@@ -2130,9 +2130,22 @@ static int __devinit smsc911x_init(struct net_device *dev)
/*
* poll the READY bit in PMT_CTRL. Any other access to the device is
* forbidden while this bit isn't set. Try for 100ms
+ *
+ * Note that this test is done before the WORD_SWAP register is
+ * programmed. So in some configurations the READY bit is at 16 before
+ * WORD_SWAP is written to. This issue is worked around by waiting
+ * until either bit 0 or bit 16 gets set in PMT_CTRL.
+ *
+ * SMSC has confirmed that checking bit 16 (marked as reserved in
+ * the datasheet) is fine since these bits "will either never be set
+ * or can only go high after READY does (so also indicate the device
+ * is ready)".
*/
- while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to)
+
+ mask = PMT_CTRL_READY_ | swahw32(PMT_CTRL_READY_);
+ while (!(smsc911x_reg_read(pdata, PMT_CTRL) & mask) && --to)
udelay(1000);
+
if (to == 0) {
pr_err("Device not READY in 100ms aborting\n");
return -ENODEV;
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 4e9810013850..66e025ad5df1 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -917,7 +917,7 @@ static int tile_net_setup_interrupts(struct net_device *dev)
ingress_irq = rc;
tile_irq_activate(ingress_irq, TILE_IRQ_PERCPU);
rc = request_irq(ingress_irq, tile_net_handle_ingress_irq,
- 0, NULL, NULL);
+ 0, "tile_net", NULL);
if (rc != 0) {
netdev_err(dev, "request_irq failed: %d\n", rc);
destroy_irq(ingress_irq);
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
index 1d04754a6637..a788501e978e 100644
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
@@ -894,6 +894,8 @@ out:
return IRQ_HANDLED;
}
+static void axienet_dma_err_handler(unsigned long data);
+
/**
* axienet_open - Driver open routine.
* @ndev: Pointer to net_device structure
@@ -942,6 +944,10 @@ static int axienet_open(struct net_device *ndev)
phy_start(lp->phy_dev);
}
+ /* Enable tasklets for Axi DMA error handling */
+ tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
+ (unsigned long) lp);
+
/* Enable interrupts for Axi DMA Tx */
ret = request_irq(lp->tx_irq, axienet_tx_irq, 0, ndev->name, ndev);
if (ret)
@@ -950,8 +956,7 @@ static int axienet_open(struct net_device *ndev)
ret = request_irq(lp->rx_irq, axienet_rx_irq, 0, ndev->name, ndev);
if (ret)
goto err_rx_irq;
- /* Enable tasklets for Axi DMA error handling */
- tasklet_enable(&lp->dma_err_tasklet);
+
return 0;
err_rx_irq:
@@ -960,6 +965,7 @@ err_tx_irq:
if (lp->phy_dev)
phy_disconnect(lp->phy_dev);
lp->phy_dev = NULL;
+ tasklet_kill(&lp->dma_err_tasklet);
dev_err(lp->dev, "request_irq() failed\n");
return ret;
}
@@ -1613,10 +1619,6 @@ static int __devinit axienet_of_probe(struct platform_device *op)
goto err_iounmap_2;
}
- tasklet_init(&lp->dma_err_tasklet, axienet_dma_err_handler,
- (unsigned long) lp);
- tasklet_disable(&lp->dma_err_tasklet);
-
return 0;
err_iounmap_2:
diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c
index 98934bdf6acf..477d6729b17f 100644
--- a/drivers/net/ethernet/xscale/ixp4xx_eth.c
+++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c
@@ -1102,10 +1102,12 @@ static int init_queues(struct port *port)
{
int i;
- if (!ports_open)
- if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
- POOL_ALLOC_SIZE, 32, 0)))
+ if (!ports_open) {
+ dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev,
+ POOL_ALLOC_SIZE, 32, 0);
+ if (!dma_pool)
return -ENOMEM;
+ }
if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
&port->desc_tab_phys)))
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 5039f08f5a5b..43e9ab4f4d7e 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -222,7 +222,7 @@ static void sirdev_config_fsm(struct work_struct *work)
break;
case SIRDEV_STATE_DONGLE_SPEED:
- if (dev->dongle_drv->reset) {
+ if (dev->dongle_drv->set_speed) {
ret = dev->dongle_drv->set_speed(dev, fsm->param);
if (ret < 0) {
fsm->result = ret;
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
index 6428fcbbdd4b..daec9b05d168 100644
--- a/drivers/net/phy/mdio-bitbang.c
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -234,7 +234,6 @@ void free_mdio_bitbang(struct mii_bus *bus)
struct mdiobb_ctrl *ctrl = bus->priv;
module_put(ctrl->ops->owner);
- mdiobus_unregister(bus);
mdiobus_free(bus);
}
EXPORT_SYMBOL(free_mdio_bitbang);
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 899274f2f9b1..2ed1140df3e9 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -185,17 +185,20 @@ static int __devinit mdio_gpio_probe(struct platform_device *pdev)
{
struct mdio_gpio_platform_data *pdata;
struct mii_bus *new_bus;
- int ret;
+ int ret, bus_id;
- if (pdev->dev.of_node)
+ if (pdev->dev.of_node) {
pdata = mdio_gpio_of_get_data(pdev);
- else
+ bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio");
+ } else {
pdata = pdev->dev.platform_data;
+ bus_id = pdev->id;
+ }
if (!pdata)
return -ENODEV;
- new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
+ new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, bus_id);
if (!new_bus)
return -ENODEV;
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index d44cca327588..ad86660fb8f9 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1794,10 +1794,12 @@ static void team_setup(struct net_device *dev)
dev->features |= NETIF_F_LLTX;
dev->features |= NETIF_F_GRO;
- dev->hw_features = NETIF_F_HW_VLAN_TX |
+ dev->hw_features = TEAM_VLAN_FEATURES |
+ NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_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 9db0171e9366..c5db428e73fa 100644
--- a/drivers/net/team/team_mode_broadcast.c
+++ b/drivers/net/team/team_mode_broadcast.c
@@ -29,8 +29,8 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
if (last) {
skb2 = skb_clone(skb, GFP_ATOMIC);
if (skb2) {
- ret = team_dev_queue_xmit(team, last,
- skb2);
+ ret = !team_dev_queue_xmit(team, last,
+ skb2);
if (!sum_ret)
sum_ret = ret;
}
@@ -39,7 +39,7 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb)
}
}
if (last) {
- ret = team_dev_queue_xmit(team, last, skb);
+ ret = !team_dev_queue_xmit(team, last, skb);
if (!sum_ret)
sum_ret = ret;
}
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 4cd582a4f625..74fab1a40156 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -540,10 +540,12 @@ advance:
(ctx->ether_desc == NULL) || (ctx->control != intf))
goto error;
- /* claim interfaces, if any */
- temp = usb_driver_claim_interface(driver, ctx->data, dev);
- if (temp)
- goto error;
+ /* claim data interface, if different from control */
+ if (ctx->data != ctx->control) {
+ temp = usb_driver_claim_interface(driver, ctx->data, dev);
+ if (temp)
+ goto error;
+ }
iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
@@ -623,6 +625,10 @@ static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
tasklet_kill(&ctx->bh);
+ /* handle devices with combined control and data interface */
+ if (ctx->control == ctx->data)
+ ctx->data = NULL;
+
/* disconnect master --> disconnect slave */
if (intf == ctx->control && ctx->data) {
usb_set_intfdata(ctx->data, NULL);
@@ -1245,6 +1251,14 @@ static const struct usb_device_id cdc_devs[] = {
.driver_info = (unsigned long) &wwan_info,
},
+ /* Huawei NCM devices disguised as vendor specific */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),
+ .driver_info = (unsigned long)&wwan_info,
+ },
+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
+ .driver_info = (unsigned long)&wwan_info,
+ },
+
/* Generic CDC-NCM devices */
{ USB_INTERFACE_INFO(USB_CLASS_COMM,
USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 3b566fa0f8e6..1ea91f4237f0 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -385,6 +385,7 @@ static const struct usb_device_id products[] = {
},
/* 3. Combined interface devices matching on interface number */
+ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */
{QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0017, 3)},
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 3286166415b4..362cb8cfeb92 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -184,7 +184,7 @@ static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
/* set the address, index & direction (read from PHY) */
phy_id &= dev->mii.phy_id_mask;
idx &= dev->mii.reg_num_mask;
- addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+ addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_;
ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
check_warn_goto_done(ret, "Error writing MII_ADDR");
@@ -221,7 +221,7 @@ static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
/* set the address, index & direction (write to PHY) */
phy_id &= dev->mii.phy_id_mask;
idx &= dev->mii.reg_num_mask;
- addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+ addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_;
ret = smsc95xx_write_reg(dev, MII_ADDR, addr);
check_warn_goto_done(ret, "Error writing MII_ADDR");
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 7b4adde93c01..8b5c61917076 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1,5 +1,5 @@
/*
- * VXLAN: Virtual eXtensiable Local Area Network
+ * VXLAN: Virtual eXtensible Local Area Network
*
* Copyright (c) 2012 Vyatta Inc.
*
@@ -50,8 +50,8 @@
#define VXLAN_N_VID (1u << 24)
#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
-/* VLAN + IP header + UDP + VXLAN */
-#define VXLAN_HEADROOM (4 + 20 + 8 + 8)
+/* IP header + UDP + VXLAN + Ethernet header */
+#define VXLAN_HEADROOM (20 + 8 + 8 + 14)
#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
@@ -1102,6 +1102,10 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
if (!tb[IFLA_MTU])
dev->mtu = lowerdev->mtu - VXLAN_HEADROOM;
+
+ /* update header length based on lower device */
+ dev->hard_header_len = lowerdev->hard_header_len +
+ VXLAN_HEADROOM;
}
if (data[IFLA_VXLAN_TOS])
diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c
index 3f575afd8cfc..760776b3d66c 100644
--- a/drivers/net/wan/ixp4xx_hss.c
+++ b/drivers/net/wan/ixp4xx_hss.c
@@ -969,10 +969,12 @@ static int init_hdlc_queues(struct port *port)
{
int i;
- if (!ports_open)
- if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
- POOL_ALLOC_SIZE, 32, 0)))
+ if (!ports_open) {
+ dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev,
+ POOL_ALLOC_SIZE, 32, 0);
+ if (!dma_pool)
return -ENOMEM;
+ }
if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
&port->desc_tab_phys)))
@@ -1363,7 +1365,7 @@ static int __devinit hss_init_one(struct platform_device *pdev)
platform_set_drvdata(pdev, port);
- netdev_info(dev, "HSS-%i\n", port->id);
+ netdev_info(dev, "initialized\n");
return 0;
err_free_netdev:
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 8e1559aba495..1829b445d0b0 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1456,7 +1456,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
switch (type) {
case ATH9K_RESET_POWER_ON:
ret = ath9k_hw_set_reset_power_on(ah);
- if (!ret)
+ if (ret)
ah->reset_power_on = true;
break;
case ATH9K_RESET_WARM:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index a6f1e8166008..481345c23ded 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -4401,7 +4401,7 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
{
-#ifndef CONFIG_BRCMFISCAN
+#ifndef CONFIG_BRCMISCAN
/* scheduled scan settings */
wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index ff8162d4c454..2d9eee93c743 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -521,7 +521,7 @@ static void iwlagn_mac_tx(struct ieee80211_hw *hw,
ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
if (iwlagn_tx_skb(priv, control->sta, skb))
- dev_kfree_skb_any(skb);
+ ieee80211_free_txskb(hw, skb);
}
static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
@@ -1354,6 +1354,20 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
vif_priv->ctx = ctx;
ctx->vif = vif;
+ /*
+ * In SNIFFER device type, the firmware reports the FCS to
+ * the host, rather than snipping it off. Unfortunately,
+ * mac80211 doesn't (yet) provide a per-packet flag for
+ * this, so that we have to set the hardware flag based
+ * on the interfaces added. As the monitor interface can
+ * only be present by itself, and will be removed before
+ * other interfaces are added, this is safe.
+ */
+ if (vif->type == NL80211_IFTYPE_MONITOR)
+ priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+ else
+ priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
err = iwl_setup_interface(priv, ctx);
if (!err || reset)
goto out;
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index 7ff3f1430678..408132cf83c1 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -2114,7 +2114,7 @@ static void iwl_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
info = IEEE80211_SKB_CB(skb);
iwl_trans_free_tx_cmd(priv->trans, info->driver_data[1]);
- dev_kfree_skb_any(skb);
+ ieee80211_free_txskb(priv->hw, skb);
}
static void iwl_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c
index 10896393e5a0..2830ea290502 100644
--- a/drivers/net/wireless/iwlwifi/dvm/rxon.c
+++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c
@@ -1012,12 +1012,12 @@ static void iwl_calc_basic_rates(struct iwl_priv *priv,
* As a consequence, it's not as complicated as it sounds, just add
* any lower rates to the ACK rate bitmap.
*/
- if (IWL_RATE_11M_INDEX < lowest_present_ofdm)
- ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
- if (IWL_RATE_5M_INDEX < lowest_present_ofdm)
- ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
- if (IWL_RATE_2M_INDEX < lowest_present_ofdm)
- ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_11M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_5M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE;
+ if (IWL_RATE_2M_INDEX < lowest_present_cck)
+ cck |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE;
/* 1M already there or needed so always add */
cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE;
diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c
index 17c8e5d82681..bb69f8f90b3b 100644
--- a/drivers/net/wireless/iwlwifi/pcie/rx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/rx.c
@@ -321,6 +321,14 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)
dma_map_page(trans->dev, page, 0,
PAGE_SIZE << trans_pcie->rx_page_order,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(trans->dev, rxb->page_dma)) {
+ rxb->page = NULL;
+ spin_lock_irqsave(&rxq->lock, flags);
+ list_add(&rxb->list, &rxq->rx_used);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ __free_pages(page, trans_pcie->rx_page_order);
+ return;
+ }
/* dma address must be no more than 36 bits */
BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
/* and also 256 byte aligned! */
@@ -488,8 +496,19 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
dma_map_page(trans->dev, rxb->page, 0,
PAGE_SIZE << trans_pcie->rx_page_order,
DMA_FROM_DEVICE);
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
+ if (dma_mapping_error(trans->dev, rxb->page_dma)) {
+ /*
+ * free the page(s) as well to not break
+ * the invariant that the items on the used
+ * list have no page(s)
+ */
+ __free_pages(rxb->page, trans_pcie->rx_page_order);
+ rxb->page = NULL;
+ list_add_tail(&rxb->list, &rxq->rx_used);
+ } else {
+ list_add_tail(&rxb->list, &rxq->rx_free);
+ rxq->free_count++;
+ }
} else
list_add_tail(&rxb->list, &rxq->rx_used);
spin_unlock_irqrestore(&rxq->lock, flags);
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 105e3af3c621..79a4ddc002d3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -480,20 +480,12 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- u16 rd_ptr, wr_ptr;
- int n_bd = trans_pcie->txq[txq_id].q.n_bd;
if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
WARN_ONCE(1, "queue %d not used", txq_id);
return;
}
- rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1);
- wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id));
-
- WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]",
- txq_id, rd_ptr, wr_ptr);
-
iwl_txq_set_inactive(trans, txq_id);
IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
}
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 8d465107f52b..ae9010ed58de 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -890,9 +890,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
return;
}
cmd_node = adapter->curr_cmd;
- if (cmd_node->wait_q_enabled)
- adapter->cmd_wait_q.status = -ETIMEDOUT;
-
if (cmd_node) {
adapter->dbg.timeout_cmd_id =
adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
@@ -938,6 +935,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
adapter->ps_mode, adapter->ps_state);
+
+ if (cmd_node->wait_q_enabled) {
+ adapter->cmd_wait_q.status = -ETIMEDOUT;
+ wake_up_interruptible(&adapter->cmd_wait_q.wait);
+ mwifiex_cancel_pending_ioctl(adapter);
+ /* reset cmd_sent flag to unblock new commands */
+ adapter->cmd_sent = false;
+ }
}
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
mwifiex_init_fw_complete(adapter);
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index fc8a9bfa1248..82cf0fa2d9f6 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -161,7 +161,6 @@ static int mwifiex_sdio_suspend(struct device *dev)
struct sdio_mmc_card *card;
struct mwifiex_adapter *adapter;
mmc_pm_flag_t pm_flag = 0;
- int hs_actived = 0;
int i;
int ret = 0;
@@ -188,12 +187,14 @@ static int mwifiex_sdio_suspend(struct device *dev)
adapter = card->adapter;
/* Enable the Host Sleep */
- hs_actived = mwifiex_enable_hs(adapter);
- if (hs_actived) {
- pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n");
- ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (!mwifiex_enable_hs(adapter)) {
+ dev_err(adapter->dev, "cmd: failed to suspend\n");
+ return -EFAULT;
}
+ dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+
/* Indicate device suspended */
adapter->is_suspended = true;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 9970c2b1b199..b7e6607e6b6d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -297,6 +297,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
/*=== Customer ID ===*/
/****** 8188CU ********/
{RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/
+ {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/
{RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/
{RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
{RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index caa011008cd0..fc24eb9b3948 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -452,29 +452,85 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
/* Grant backend access to each skb fragment page. */
for (i = 0; i < frags; i++) {
skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+ struct page *page = skb_frag_page(frag);
- tx->flags |= XEN_NETTXF_more_data;
+ len = skb_frag_size(frag);
+ offset = frag->page_offset;
- id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
- np->tx_skbs[id].skb = skb_get(skb);
- tx = RING_GET_REQUEST(&np->tx, prod++);
- tx->id = id;
- ref = gnttab_claim_grant_reference(&np->gref_tx_head);
- BUG_ON((signed short)ref < 0);
+ /* Data must not cross a page boundary. */
+ BUG_ON(len + offset > PAGE_SIZE<<compound_order(page));
- mfn = pfn_to_mfn(page_to_pfn(skb_frag_page(frag)));
- gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
- mfn, GNTMAP_readonly);
+ /* Skip unused frames from start of page */
+ page += offset >> PAGE_SHIFT;
+ offset &= ~PAGE_MASK;
- tx->gref = np->grant_tx_ref[id] = ref;
- tx->offset = frag->page_offset;
- tx->size = skb_frag_size(frag);
- tx->flags = 0;
+ while (len > 0) {
+ unsigned long bytes;
+
+ BUG_ON(offset >= PAGE_SIZE);
+
+ bytes = PAGE_SIZE - offset;
+ if (bytes > len)
+ bytes = len;
+
+ tx->flags |= XEN_NETTXF_more_data;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist,
+ np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = pfn_to_mfn(page_to_pfn(page));
+ gnttab_grant_foreign_access_ref(ref,
+ np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = bytes;
+ tx->flags = 0;
+
+ offset += bytes;
+ len -= bytes;
+
+ /* Next frame */
+ if (offset == PAGE_SIZE && len) {
+ BUG_ON(!PageCompound(page));
+ page++;
+ offset = 0;
+ }
+ }
}
np->tx.req_prod_pvt = prod;
}
+/*
+ * Count how many ring slots are required to send the frags of this
+ * skb. Each frag might be a compound page.
+ */
+static int xennet_count_skb_frag_slots(struct sk_buff *skb)
+{
+ int i, frags = skb_shinfo(skb)->nr_frags;
+ int pages = 0;
+
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+ unsigned long size = skb_frag_size(frag);
+ unsigned long offset = frag->page_offset;
+
+ /* Skip unused frames from start of page */
+ offset &= ~PAGE_MASK;
+
+ pages += PFN_UP(offset + size);
+ }
+
+ return pages;
+}
+
static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned short id;
@@ -487,23 +543,23 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
grant_ref_t ref;
unsigned long mfn;
int notify;
- int frags = skb_shinfo(skb)->nr_frags;
+ int slots;
unsigned int offset = offset_in_page(data);
unsigned int len = skb_headlen(skb);
unsigned long flags;
- frags += DIV_ROUND_UP(offset + len, PAGE_SIZE);
- if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
- printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
- frags);
- dump_stack();
+ slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) +
+ xennet_count_skb_frag_slots(skb);
+ if (unlikely(slots > MAX_SKB_FRAGS + 1)) {
+ net_alert_ratelimited(
+ "xennet: skb rides the rocket: %d slots\n", slots);
goto drop;
}
spin_lock_irqsave(&np->tx_lock, flags);
if (unlikely(!netif_carrier_ok(dev) ||
- (frags > 1 && !xennet_can_sg(dev)) ||
+ (slots > 1 && !xennet_can_sg(dev)) ||
netif_needs_gso(skb, netif_skb_features(skb)))) {
spin_unlock_irqrestore(&np->tx_lock, flags);
goto drop;
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 97c440a8cd61..30ae18a03a9c 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -698,13 +698,14 @@ static void pn533_wq_cmd(struct work_struct *work)
cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue);
+ list_del(&cmd->queue);
+
mutex_unlock(&dev->cmd_lock);
__pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame,
cmd->in_frame_len, cmd->cmd_complete,
cmd->arg, cmd->flags);
- list_del(&cmd->queue);
kfree(cmd);
}
@@ -1678,11 +1679,14 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
- struct pn533_cmd_jump_dep *cmd;
struct pn533_cmd_jump_dep_response *resp;
struct nfc_target nfc_target;
u8 target_gt_len;
int rc;
+ struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg;
+ u8 active = cmd->active;
+
+ kfree(arg);
if (params_len == -ENOENT) {
nfc_dev_dbg(&dev->interface->dev, "");
@@ -1704,7 +1708,6 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
}
resp = (struct pn533_cmd_jump_dep_response *) params;
- cmd = (struct pn533_cmd_jump_dep *) arg;
rc = resp->status & PN533_CMD_RET_MASK;
if (rc != PN533_CMD_RET_SUCCESS) {
nfc_dev_err(&dev->interface->dev,
@@ -1734,7 +1737,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
if (rc == 0)
rc = nfc_dep_link_is_up(dev->nfc_dev,
dev->nfc_dev->targets[0].idx,
- !cmd->active, NFC_RF_INITIATOR);
+ !active, NFC_RF_INITIATOR);
return 0;
}
@@ -1819,12 +1822,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
dev->in_maxlen, pn533_in_dep_link_up_complete,
cmd, GFP_KERNEL);
- if (rc)
- goto out;
-
-
-out:
- kfree(cmd);
+ if (rc < 0)
+ kfree(cmd);
return rc;
}
@@ -2078,8 +2077,12 @@ error:
static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
+ struct sk_buff *skb_out = arg;
+
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+ dev_kfree_skb(skb_out);
+
if (params_len < 0) {
nfc_dev_err(&dev->interface->dev,
"Error %d when sending data",
@@ -2117,7 +2120,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
dev->in_maxlen, pn533_tm_send_complete,
- NULL, GFP_KERNEL);
+ skb, GFP_KERNEL);
if (rc) {
nfc_dev_err(&dev->interface->dev,
"Error %d when trying to send data", rc);
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d96caefd914a..390ab69ea569 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,6 +26,15 @@ config DEBUG_PINCTRL
help
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
+config PINCTRL_AT91
+ bool "AT91 pinctrl driver"
+ depends on OF
+ depends on ARCH_AT91
+ select PINMUX
+ select PINCONF
+ help
+ Say Y here to enable the at91 pinctrl driver
+
config PINCTRL_BCM2835
bool
select PINMUX
@@ -87,21 +96,18 @@ config PINCTRL_MMP2
bool "MMP2 pin controller driver"
depends on ARCH_MMP
select PINCTRL_PXA3xx
- select PINCONF
config PINCTRL_MXS
bool
+ select PINMUX
+ select PINCONF
config PINCTRL_IMX23
bool
- select PINMUX
- select PINCONF
select PINCTRL_MXS
config PINCTRL_IMX28
bool
- select PINMUX
- select PINCONF
select PINCTRL_MXS
config PINCTRL_NOMADIK
@@ -126,13 +132,11 @@ config PINCTRL_PXA168
bool "PXA168 pin controller driver"
depends on ARCH_MMP
select PINCTRL_PXA3xx
- select PINCONF
config PINCTRL_PXA910
bool "PXA910 pin controller driver"
depends on ARCH_MMP
select PINCTRL_PXA3xx
- select PINCONF
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
@@ -143,23 +147,21 @@ config PINCTRL_SINGLE
This selects the device tree based generic pinctrl driver.
config PINCTRL_SIRF
- bool "CSR SiRFprimaII pin controller driver"
- depends on ARCH_PRIMA2
+ bool "CSR SiRFprimaII/SiRFmarco pin controller driver"
+ depends on ARCH_SIRF
select PINMUX
config PINCTRL_TEGRA
bool
+ select PINMUX
+ select PINCONF
config PINCTRL_TEGRA20
bool
- select PINMUX
- select PINCONF
select PINCTRL_TEGRA
config PINCTRL_TEGRA30
bool
- select PINMUX
- select PINCONF
select PINCTRL_TEGRA
config PINCTRL_U300
@@ -178,7 +180,7 @@ config PINCTRL_COH901
ports of 8 GPIO pins each.
config PINCTRL_SAMSUNG
- bool "Samsung pinctrl driver"
+ bool
depends on OF && GPIOLIB
select PINMUX
select PINCONF
@@ -188,27 +190,7 @@ config PINCTRL_EXYNOS4
depends on OF && GPIOLIB
select PINCTRL_SAMSUNG
-config PINCTRL_MVEBU
- bool
- depends on ARCH_MVEBU
- select PINMUX
- select PINCONF
-
-config PINCTRL_DOVE
- bool
- select PINCTRL_MVEBU
-
-config PINCTRL_KIRKWOOD
- bool
- select PINCTRL_MVEBU
-
-config PINCTRL_ARMADA_370
- bool
- select PINCTRL_MVEBU
-
-config PINCTRL_ARMADA_XP
- bool
- select PINCTRL_MVEBU
+source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/spear/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index f395ba5cec25..f95f5ed923be 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
obj-$(CONFIG_PINCTRL) += devicetree.o
endif
obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
+obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o
@@ -36,12 +37,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o
-obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
-obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
-obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
-obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
-obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
+obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
index 2e39c04fc16b..5cdee8669ea3 100644
--- a/drivers/pinctrl/core.c
+++ b/drivers/pinctrl/core.c
@@ -345,6 +345,62 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
}
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);
+
+ /*
+ * 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)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ pinctrl_add_gpio_range(pctldev, range);
+ return pctldev;
+}
+EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
+
+/**
+ * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin
+ * @pctldev: the pin controller device to look in
+ * @pin: a controller-local number to find the range for
+ */
+struct pinctrl_gpio_range *
+pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
+ unsigned int pin)
+{
+ struct pinctrl_gpio_range *range = NULL;
+
+ /* 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) {
+ return range;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
+
+/**
+ * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller
+ * @pctldev: pin controller device to remove the range from
+ * @range: the GPIO range to remove
+ */
+void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range)
+{
+ mutex_lock(&pinctrl_mutex);
+ list_del(&range->node);
+ mutex_unlock(&pinctrl_mutex);
+}
+EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range);
+
/**
* pinctrl_get_group_selector() - returns the group selector for a group
* @pctldev: the pin controller handling the group
@@ -563,6 +619,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map)
return -EPROBE_DEFER;
}
+ setting->dev_name = map->dev_name;
+
switch (map->type) {
case PIN_MAP_TYPE_MUX_GROUP:
ret = pinmux_map_to_setting(map, setting);
diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h
index 1f40ff68a8c4..12f5694f3d5d 100644
--- a/drivers/pinctrl/core.h
+++ b/drivers/pinctrl/core.h
@@ -105,12 +105,14 @@ struct pinctrl_setting_configs {
* @type: the type of setting
* @pctldev: pin control device handling to be programmed. Not used for
* PIN_MAP_TYPE_DUMMY_STATE.
+ * @dev_name: the name of the device using this state
* @data: Data specific to the setting type
*/
struct pinctrl_setting {
struct list_head node;
enum pinctrl_map_type type;
struct pinctrl_dev *pctldev;
+ const char *dev_name;
union {
struct pinctrl_setting_mux mux;
struct pinctrl_setting_configs configs;
diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c
index fcb1de45473c..fe2d1af7cfa0 100644
--- a/drivers/pinctrl/devicetree.c
+++ b/drivers/pinctrl/devicetree.c
@@ -106,6 +106,17 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np)
return NULL;
}
+struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
+{
+ struct pinctrl_dev *pctldev;
+
+ pctldev = find_pinctrl_by_of_node(np);
+ if (!pctldev)
+ return NULL;
+
+ return pctldev;
+}
+
static int dt_to_map_one_config(struct pinctrl *p, const char *statename,
struct device_node *np_config)
{
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
new file mode 100644
index 000000000000..366fa541ee91
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -0,0 +1,24 @@
+if PLAT_ORION
+
+config PINCTRL_MVEBU
+ bool
+ select PINMUX
+ select PINCONF
+
+config PINCTRL_DOVE
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_KIRKWOOD
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_370
+ bool
+ select PINCTRL_MVEBU
+
+config PINCTRL_ARMADA_XP
+ bool
+ select PINCTRL_MVEBU
+
+endif
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
new file mode 100644
index 000000000000..37c253297af0
--- /dev/null
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
+obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o
+obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o
+obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
+obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o
diff --git a/drivers/pinctrl/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
index c907647de6ad..c907647de6ad 100644
--- a/drivers/pinctrl/pinctrl-armada-370.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c
diff --git a/drivers/pinctrl/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
index 40bd52a46b4e..40bd52a46b4e 100644
--- a/drivers/pinctrl/pinctrl-armada-xp.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c
diff --git a/drivers/pinctrl/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c
index ffe74b27d66d..ffe74b27d66d 100644
--- a/drivers/pinctrl/pinctrl-dove.c
+++ b/drivers/pinctrl/mvebu/pinctrl-dove.c
diff --git a/drivers/pinctrl/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
index 9a74ef674a0e..9a74ef674a0e 100644
--- a/drivers/pinctrl/pinctrl-kirkwood.c
+++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c
diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 8e6266c6249a..6c44b7e8964c 100644
--- a/drivers/pinctrl/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -24,7 +24,6 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
-#include "core.h"
#include "pinctrl-mvebu.h"
#define MPPS_PER_REG 8
diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
index 90bd3beee860..90bd3beee860 100644
--- a/drivers/pinctrl/pinctrl-mvebu.h
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 33fbaeaa65dd..833a36458157 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -41,6 +41,7 @@ struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
+ PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
new file mode 100644
index 000000000000..c5e757157183
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -0,0 +1,1634 @@
+/*
+ * at91 pinctrl driver based on at91 pinmux core
+ *
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/at91_pio.h>
+
+#include "core.h"
+
+#define MAX_NB_GPIO_PER_BANK 32
+
+struct at91_pinctrl_mux_ops;
+
+struct at91_gpio_chip {
+ struct gpio_chip chip;
+ struct pinctrl_gpio_range range;
+ struct at91_gpio_chip *next; /* Bank sharing same clock */
+ int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
+ int pioc_virq; /* PIO bank Linux virtual interrupt */
+ int pioc_idx; /* PIO bank index */
+ void __iomem *regbase; /* PIO bank virtual address */
+ struct clk *clock; /* associated clock */
+ struct irq_domain *domain; /* associated irq domain */
+ struct at91_pinctrl_mux_ops *ops; /* ops */
+};
+
+#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
+
+static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
+
+static int gpio_banks;
+
+#define PULL_UP (1 << 0)
+#define MULTI_DRIVE (1 << 1)
+#define DEGLITCH (1 << 2)
+#define PULL_DOWN (1 << 3)
+#define DIS_SCHMIT (1 << 4)
+#define DEBOUNCE (1 << 16)
+#define DEBOUNCE_VAL_SHIFT 17
+#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
+
+/**
+ * struct at91_pmx_func - describes AT91 pinmux functions
+ * @name: the name of this specific function
+ * @groups: corresponding pin groups
+ * @ngroups: the number of groups
+ */
+struct at91_pmx_func {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+enum at91_mux {
+ AT91_MUX_GPIO = 0,
+ AT91_MUX_PERIPH_A = 1,
+ AT91_MUX_PERIPH_B = 2,
+ AT91_MUX_PERIPH_C = 3,
+ AT91_MUX_PERIPH_D = 4,
+};
+
+/**
+ * struct at91_pmx_pin - describes an At91 pin mux
+ * @bank: the bank of the pin
+ * @pin: the pin number in the @bank
+ * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function.
+ * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc...
+ */
+struct at91_pmx_pin {
+ uint32_t bank;
+ uint32_t pin;
+ enum at91_mux mux;
+ unsigned long conf;
+};
+
+/**
+ * struct at91_pin_group - describes an At91 pin group
+ * @name: the name of this specific pin group
+ * @pins_conf: the mux mode for each pin in this group. The size of this
+ * array is the same as pins.
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @npins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ */
+struct at91_pin_group {
+ const char *name;
+ struct at91_pmx_pin *pins_conf;
+ unsigned int *pins;
+ unsigned npins;
+};
+
+/**
+ * struct at91_pinctrl_mux_ops - describes an At91 mux ops group
+ * on new IP with support for periph C and D the way to mux in
+ * periph A and B has changed
+ * So provide the right call back
+ * if not present means the IP does not support it
+ * @get_periph: return the periph mode configured
+ * @mux_A_periph: mux as periph A
+ * @mux_B_periph: mux as periph B
+ * @mux_C_periph: mux as periph C
+ * @mux_D_periph: mux as periph D
+ * @get_deglitch: get deglitch status
+ * @set_deglitch: enable/disable deglitch
+ * @get_debounce: get debounce status
+ * @set_debounce: enable/disable debounce
+ * @get_pulldown: get pulldown status
+ * @set_pulldown: enable/disable pulldown
+ * @get_schmitt_trig: get schmitt trigger status
+ * @disable_schmitt_trig: disable schmitt trigger
+ * @irq_type: return irq type
+ */
+struct at91_pinctrl_mux_ops {
+ enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_A_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_B_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_C_periph)(void __iomem *pio, unsigned mask);
+ void (*mux_D_periph)(void __iomem *pio, unsigned mask);
+ bool (*get_deglitch)(void __iomem *pio, unsigned pin);
+ void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on);
+ bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div);
+ void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div);
+ bool (*get_pulldown)(void __iomem *pio, unsigned pin);
+ void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on);
+ bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin);
+ void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask);
+ /* irq */
+ int (*irq_type)(struct irq_data *d, unsigned type);
+};
+
+static int gpio_irq_type(struct irq_data *d, unsigned type);
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type);
+
+struct at91_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+
+ int nbanks;
+
+ uint32_t *mux_mask;
+ int nmux;
+
+ struct at91_pmx_func *functions;
+ int nfunctions;
+
+ struct at91_pin_group *groups;
+ int ngroups;
+
+ struct at91_pinctrl_mux_ops *ops;
+};
+
+static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name(
+ const struct at91_pinctrl *info,
+ const char *name)
+{
+ const struct at91_pin_group *grp = NULL;
+ int i;
+
+ for (i = 0; i < info->ngroups; i++) {
+ if (strcmp(info->groups[i].name, name))
+ continue;
+
+ grp = &info->groups[i];
+ dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]);
+ break;
+ }
+
+ return grp;
+}
+
+static int at91_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->ngroups;
+}
+
+static const char *at91_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->groups[selector].name;
+}
+
+static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *npins)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ if (selector >= info->ngroups)
+ return -EINVAL;
+
+ *pins = info->groups[selector].pins;
+ *npins = info->groups[selector].npins;
+
+ return 0;
+}
+
+static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, "%s", dev_name(pctldev->dev));
+}
+
+static int at91_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct at91_pin_group *grp;
+ struct pinctrl_map *new_map;
+ struct device_node *parent;
+ int map_num = 1;
+ int i;
+
+ /*
+ * first find the group of this node and check if we need create
+ * config maps for pins
+ */
+ grp = at91_pinctrl_find_group_by_name(info, np->name);
+ if (!grp) {
+ dev_err(info->dev, "unable to find group for node %s\n",
+ np->name);
+ return -EINVAL;
+ }
+
+ map_num += grp->npins;
+ new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL);
+ if (!new_map)
+ return -ENOMEM;
+
+ *map = new_map;
+ *num_maps = map_num;
+
+ /* create mux map */
+ parent = of_get_parent(np);
+ if (!parent) {
+ kfree(new_map);
+ return -EINVAL;
+ }
+ new_map[0].type = PIN_MAP_TYPE_MUX_GROUP;
+ new_map[0].data.mux.function = parent->name;
+ new_map[0].data.mux.group = np->name;
+ of_node_put(parent);
+
+ /* create config map */
+ new_map++;
+ for (i = 0; i < grp->npins; i++) {
+ new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ new_map[i].data.configs.group_or_pin =
+ pin_get_name(pctldev, grp->pins[i]);
+ new_map[i].data.configs.configs = &grp->pins_conf[i].conf;
+ new_map[i].data.configs.num_configs = 1;
+ }
+
+ dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n",
+ (*map)->data.mux.function, (*map)->data.mux.group, map_num);
+
+ return 0;
+}
+
+static void at91_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+}
+
+static 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,
+ .pin_dbg_show = at91_pin_dbg_show,
+ .dt_node_to_map = at91_dt_node_to_map,
+ .dt_free_map = at91_dt_free_map,
+};
+
+static void __iomem * pin_to_controller(struct at91_pinctrl *info,
+ unsigned int bank)
+{
+ return gpio_chips[bank]->regbase;
+}
+
+static inline int pin_to_bank(unsigned pin)
+{
+ return pin /= MAX_NB_GPIO_PER_BANK;
+}
+
+static unsigned pin_to_mask(unsigned int pin)
+{
+ return 1 << pin;
+}
+
+static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_IDR);
+}
+
+static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin)
+{
+ return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on)
+{
+ writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR));
+}
+
+static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin)
+{
+ return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on)
+{
+ writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR));
+}
+
+static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_ASR);
+}
+
+static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_BSR);
+}
+
+static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask)
+{
+
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask,
+ pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
+ pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask,
+ pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask,
+ pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+}
+
+static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
+ writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
+}
+
+static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask)
+{
+ unsigned select;
+
+ if (readl_relaxed(pio + PIO_PSR) & mask)
+ return AT91_MUX_GPIO;
+
+ select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask);
+ select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1);
+
+ return select + 1;
+}
+
+static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask)
+{
+ unsigned select;
+
+ if (readl_relaxed(pio + PIO_PSR) & mask)
+ return AT91_MUX_GPIO;
+
+ select = readl_relaxed(pio + PIO_ABSR) & mask;
+
+ return select + 1;
+}
+
+static bool at91_mux_get_deglitch(void __iomem *pio, unsigned pin)
+{
+ return (__raw_readl(pio + PIO_IFSR) >> pin) & 0x1;
+}
+
+static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on)
+{
+ __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
+}
+
+static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on)
+{
+ if (is_on)
+ __raw_writel(mask, pio + PIO_IFSCDR);
+ at91_mux_set_deglitch(pio, mask, is_on);
+}
+
+static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div)
+{
+ *div = __raw_readl(pio + PIO_SCDR);
+
+ return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1;
+}
+
+static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask,
+ bool is_on, u32 div)
+{
+ if (is_on) {
+ __raw_writel(mask, pio + PIO_IFSCER);
+ __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
+ __raw_writel(mask, pio + PIO_IFER);
+ } else {
+ __raw_writel(mask, pio + PIO_IFDR);
+ }
+}
+
+static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin)
+{
+ return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1;
+}
+
+static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on)
+{
+ __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
+}
+
+static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask)
+{
+ __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
+}
+
+static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin)
+{
+ return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1;
+}
+
+static struct at91_pinctrl_mux_ops at91rm9200_ops = {
+ .get_periph = at91_mux_get_periph,
+ .mux_A_periph = at91_mux_set_A_periph,
+ .mux_B_periph = at91_mux_set_B_periph,
+ .get_deglitch = at91_mux_get_deglitch,
+ .set_deglitch = at91_mux_set_deglitch,
+ .irq_type = gpio_irq_type,
+};
+
+static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
+ .get_periph = at91_mux_pio3_get_periph,
+ .mux_A_periph = at91_mux_pio3_set_A_periph,
+ .mux_B_periph = at91_mux_pio3_set_B_periph,
+ .mux_C_periph = at91_mux_pio3_set_C_periph,
+ .mux_D_periph = at91_mux_pio3_set_D_periph,
+ .get_deglitch = at91_mux_get_deglitch,
+ .set_deglitch = at91_mux_pio3_set_deglitch,
+ .get_debounce = at91_mux_pio3_get_debounce,
+ .set_debounce = at91_mux_pio3_set_debounce,
+ .get_pulldown = at91_mux_pio3_get_pulldown,
+ .set_pulldown = at91_mux_pio3_set_pulldown,
+ .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig,
+ .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
+ .irq_type = alt_gpio_irq_type,
+};
+
+static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin)
+{
+ if (pin->mux) {
+ dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n",
+ pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf);
+ } else {
+ dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n",
+ pin->bank + 'A', pin->pin, pin->conf);
+ }
+}
+
+static int pin_check_config(struct at91_pinctrl *info, const char* name,
+ int index, const struct at91_pmx_pin *pin)
+{
+ int mux;
+
+ /* check if it's a valid config */
+ if (pin->bank >= info->nbanks) {
+ dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
+ name, index, pin->bank, info->nbanks);
+ return -EINVAL;
+ }
+
+ if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
+ dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
+ name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
+ return -EINVAL;
+ }
+
+ if (!pin->mux)
+ return 0;
+
+ mux = pin->mux - 1;
+
+ if (mux >= info->nmux) {
+ dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n",
+ name, index, mux, info->nmux);
+ return -EINVAL;
+ }
+
+ if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) {
+ dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n",
+ name, index, mux, pin->bank + 'A', pin->pin);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask)
+{
+ writel_relaxed(mask, pio + PIO_PDR);
+}
+
+static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input)
+{
+ writel_relaxed(mask, pio + PIO_PER);
+ writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER));
+}
+
+static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
+ const struct at91_pmx_pin *pin;
+ uint32_t npins = info->groups[group].npins;
+ int i, ret;
+ unsigned mask;
+ void __iomem *pio;
+
+ dev_dbg(info->dev, "enable function %s group %s\n",
+ info->functions[selector].name, info->groups[group].name);
+
+ /* first check that all the pins of the group are valid with a valid
+ * paramter */
+ for (i = 0; i < npins; i++) {
+ pin = &pins_conf[i];
+ ret = pin_check_config(info, info->groups[group].name, i, pin);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < npins; i++) {
+ pin = &pins_conf[i];
+ at91_pin_dbg(info->dev, pin);
+ pio = pin_to_controller(info, pin->bank);
+ mask = pin_to_mask(pin->pin);
+ at91_mux_disable_interrupt(pio, mask);
+ switch(pin->mux) {
+ case AT91_MUX_GPIO:
+ at91_mux_gpio_enable(pio, mask, 1);
+ break;
+ case AT91_MUX_PERIPH_A:
+ info->ops->mux_A_periph(pio, mask);
+ break;
+ case AT91_MUX_PERIPH_B:
+ info->ops->mux_B_periph(pio, mask);
+ break;
+ case AT91_MUX_PERIPH_C:
+ if (!info->ops->mux_C_periph)
+ return -EINVAL;
+ info->ops->mux_C_periph(pio, mask);
+ break;
+ case AT91_MUX_PERIPH_D:
+ if (!info->ops->mux_D_periph)
+ return -EINVAL;
+ info->ops->mux_D_periph(pio, mask);
+ break;
+ }
+ if (pin->mux)
+ at91_mux_gpio_disable(pio, mask);
+ }
+
+ return 0;
+}
+
+static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned group)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf;
+ const struct at91_pmx_pin *pin;
+ uint32_t npins = info->groups[group].npins;
+ int i;
+ unsigned mask;
+ void __iomem *pio;
+
+ for (i = 0; i < npins; i++) {
+ pin = &pins_conf[i];
+ at91_pin_dbg(info->dev, pin);
+ pio = pin_to_controller(info, pin->bank);
+ mask = pin_to_mask(pin->pin);
+ at91_mux_gpio_enable(pio, mask, 1);
+ }
+}
+
+static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->nfunctions;
+}
+
+static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ return info->functions[selector].name;
+}
+
+static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = info->functions[selector].groups;
+ *num_groups = info->functions[selector].ngroups;
+
+ return 0;
+}
+
+static int at91_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ struct at91_gpio_chip *at91_chip;
+ struct gpio_chip *chip;
+ unsigned mask;
+
+ if (!range) {
+ dev_err(npct->dev, "invalid range\n");
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "missing GPIO chip in range\n");
+ return -EINVAL;
+ }
+ chip = range->gc;
+ at91_chip = container_of(chip, struct at91_gpio_chip, chip);
+
+ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
+
+ mask = 1 << (offset - chip->base);
+
+ dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n",
+ offset, 'A' + range->id, offset - chip->base, mask);
+
+ writel_relaxed(mask, at91_chip->regbase + PIO_PER);
+
+ return 0;
+}
+
+static void at91_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
+ /* Set the pin to some default state, GPIO is usually default */
+}
+
+static 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,
+ .enable = at91_pmx_enable,
+ .disable = at91_pmx_disable,
+ .gpio_request_enable = at91_gpio_request_enable,
+ .gpio_disable_free = at91_gpio_disable_free,
+};
+
+static int at91_pinconf_get(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long *config)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ void __iomem *pio;
+ unsigned pin;
+ int div;
+
+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config);
+ pio = pin_to_controller(info, pin_to_bank(pin_id));
+ pin = pin_id % MAX_NB_GPIO_PER_BANK;
+
+ if (at91_mux_get_multidrive(pio, pin))
+ *config |= MULTI_DRIVE;
+
+ if (at91_mux_get_pullup(pio, pin))
+ *config |= PULL_UP;
+
+ if (info->ops->get_deglitch && info->ops->get_deglitch(pio, pin))
+ *config |= DEGLITCH;
+ if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div))
+ *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT);
+ if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin))
+ *config |= PULL_DOWN;
+ if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin))
+ *config |= DIS_SCHMIT;
+
+ return 0;
+}
+
+static int at91_pinconf_set(struct pinctrl_dev *pctldev,
+ unsigned pin_id, unsigned long config)
+{
+ struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ unsigned mask;
+ void __iomem *pio;
+
+ dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config);
+ pio = pin_to_controller(info, pin_to_bank(pin_id));
+ mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
+
+ if (config & PULL_UP && config & PULL_DOWN)
+ return -EINVAL;
+
+ at91_mux_set_pullup(pio, mask, config & PULL_UP);
+ at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE);
+ if (info->ops->set_deglitch)
+ info->ops->set_deglitch(pio, mask, config & DEGLITCH);
+ if (info->ops->set_debounce)
+ info->ops->set_debounce(pio, mask, config & DEBOUNCE,
+ (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT);
+ if (info->ops->set_pulldown)
+ info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
+ if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
+ info->ops->disable_schmitt_trig(pio, mask);
+
+ return 0;
+}
+
+static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin_id)
+{
+
+}
+
+static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned group)
+{
+}
+
+static 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,
+ .pin_config_group_dbg_show = at91_pinconf_group_dbg_show,
+};
+
+static struct pinctrl_desc at91_pinctrl_desc = {
+ .pctlops = &at91_pctrl_ops,
+ .pmxops = &at91_pmx_ops,
+ .confops = &at91_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static const char *gpio_compat = "atmel,at91rm9200-gpio";
+
+static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info,
+ struct device_node *np)
+{
+ struct device_node *child;
+
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat)) {
+ info->nbanks++;
+ } else {
+ info->nfunctions++;
+ info->ngroups += of_get_child_count(child);
+ }
+ }
+}
+
+static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info,
+ struct device_node *np)
+{
+ int ret = 0;
+ int size;
+ const const __be32 *list;
+
+ list = of_get_property(np, "atmel,mux-mask", &size);
+ if (!list) {
+ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
+ return -EINVAL;
+ }
+
+ size /= sizeof(*list);
+ if (!size || size % info->nbanks) {
+ dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
+ return -EINVAL;
+ }
+ info->nmux = size / info->nbanks;
+
+ info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
+ if (!info->mux_mask) {
+ dev_err(info->dev, "could not alloc mux_mask\n");
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32_array(np, "atmel,mux-mask",
+ info->mux_mask, size);
+ if (ret)
+ dev_err(info->dev, "can not read the mux-mask of %d\n", size);
+ return ret;
+}
+
+static int __devinit at91_pinctrl_parse_groups(struct device_node *np,
+ struct at91_pin_group *grp,
+ struct at91_pinctrl *info,
+ u32 index)
+{
+ struct at91_pmx_pin *pin;
+ int size;
+ const const __be32 *list;
+ int i, j;
+
+ dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
+
+ /* Initialise group */
+ grp->name = np->name;
+
+ /*
+ * the binding format is atmel,pins = <bank pin mux CONFIG ...>,
+ * do sanity check and calculate pins number
+ */
+ list = of_get_property(np, "atmel,pins", &size);
+ /* we do not check return since it's safe node passed down */
+ size /= sizeof(*list);
+ if (!size || size % 4) {
+ dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n");
+ return -EINVAL;
+ }
+
+ grp->npins = size / 4;
+ pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin),
+ GFP_KERNEL);
+ grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!grp->pins_conf || !grp->pins)
+ return -ENOMEM;
+
+ for (i = 0, j = 0; i < size; i += 4, j++) {
+ pin->bank = be32_to_cpu(*list++);
+ pin->pin = be32_to_cpu(*list++);
+ grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin;
+ pin->mux = be32_to_cpu(*list++);
+ pin->conf = be32_to_cpu(*list++);
+
+ at91_pin_dbg(info->dev, pin);
+ pin++;
+ }
+
+ return 0;
+}
+
+static int __devinit at91_pinctrl_parse_functions(struct device_node *np,
+ struct at91_pinctrl *info, u32 index)
+{
+ struct device_node *child;
+ struct at91_pmx_func *func;
+ struct at91_pin_group *grp;
+ int ret;
+ static u32 grp_index;
+ u32 i = 0;
+
+ dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name);
+
+ func = &info->functions[index];
+
+ /* Initialise function */
+ func->name = np->name;
+ func->ngroups = of_get_child_count(np);
+ if (func->ngroups <= 0) {
+ dev_err(info->dev, "no groups defined\n");
+ return -EINVAL;
+ }
+ func->groups = devm_kzalloc(info->dev,
+ func->ngroups * sizeof(char *), GFP_KERNEL);
+ if (!func->groups)
+ return -ENOMEM;
+
+ for_each_child_of_node(np, child) {
+ func->groups[i] = child->name;
+ grp = &info->groups[grp_index++];
+ ret = at91_pinctrl_parse_groups(child, grp, info, i++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct of_device_id at91_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
+ { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
+ { /* sentinel */ }
+};
+
+static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev,
+ struct at91_pinctrl *info)
+{
+ int ret = 0;
+ int i, j;
+ uint32_t *tmp;
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+
+ if (!np)
+ return -ENODEV;
+
+ info->dev = &pdev->dev;
+ info->ops = (struct at91_pinctrl_mux_ops*)
+ of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
+ at91_pinctrl_child_count(info, np);
+
+ if (info->nbanks < 1) {
+ dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n");
+ return -EINVAL;
+ }
+
+ ret = at91_pinctrl_mux_mask(info, np);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux);
+
+ dev_dbg(&pdev->dev, "mux-mask\n");
+ tmp = info->mux_mask;
+ for (i = 0; i < info->nbanks; i++) {
+ for (j = 0; j < info->nmux; j++, tmp++) {
+ dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
+ }
+ }
+
+ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+ info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func),
+ GFP_KERNEL);
+ if (!info->functions)
+ return -ENOMEM;
+
+ info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group),
+ GFP_KERNEL);
+ if (!info->groups)
+ return -ENOMEM;
+
+ dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
+ dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
+ dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
+
+ i = 0;
+
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, gpio_compat))
+ continue;
+ ret = at91_pinctrl_parse_functions(child, info, i++);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to parse function\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __devinit at91_pinctrl_probe(struct platform_device *pdev)
+{
+ struct at91_pinctrl *info;
+ struct pinctrl_pin_desc *pdesc;
+ int ret, i, j ,k;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ ret = at91_pinctrl_probe_dt(pdev, info);
+ if (ret)
+ return ret;
+
+ /*
+ * We need all the GPIO drivers to probe FIRST, or we will not be able
+ * to obtain references to the struct gpio_chip * for them, and we
+ * need this to proceed.
+ */
+ for (i = 0; i < info->nbanks; i++) {
+ if (!gpio_chips[i]) {
+ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
+ devm_kfree(&pdev->dev, info);
+ return -EPROBE_DEFER;
+ }
+ }
+
+ at91_pinctrl_desc.name = dev_name(&pdev->dev);
+ at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
+ at91_pinctrl_desc.pins = pdesc =
+ devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
+
+ if (!at91_pinctrl_desc.pins)
+ return -ENOMEM;
+
+ for (i = 0 , k = 0; i < info->nbanks; i++) {
+ for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
+ pdesc->number = k;
+ pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
+ pdesc++;
+ }
+ }
+
+ platform_set_drvdata(pdev, info);
+ info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info);
+
+ if (!info->pctl) {
+ dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* We will handle a range of GPIO pins */
+ for (i = 0; i < info->nbanks; i++)
+ pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
+
+ dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static int __devexit at91_pinctrl_remove(struct platform_device *pdev)
+{
+ struct at91_pinctrl *info = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(info->pctl);
+
+ return 0;
+}
+
+static int at91_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;
+ int bank = chip->base / chip->ngpio;
+
+ dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__,
+ 'A' + bank, offset, gpio);
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void at91_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
+static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ writel_relaxed(mask, pio + PIO_ODR);
+ return 0;
+}
+
+static int at91_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+ u32 pdsr;
+
+ pdsr = readl_relaxed(pio + PIO_PDSR);
+ return (pdsr & mask) != 0;
+}
+
+static void at91_gpio_set(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+}
+
+static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int val)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << offset;
+
+ writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR));
+ writel_relaxed(mask, pio + PIO_OER);
+
+ return 0;
+}
+
+static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ int virq;
+
+ if (offset < chip->ngpio)
+ virq = irq_create_mapping(at91_gpio->domain, offset);
+ else
+ virq = -ENXIO;
+
+ dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+ chip->label, offset + chip->base, virq);
+ return virq;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ enum at91_mux mode;
+ int i;
+ struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+ void __iomem *pio = at91_gpio->regbase;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ unsigned pin = chip->base + i;
+ unsigned mask = pin_to_mask(pin);
+ const char *gpio_label;
+ u32 pdsr;
+
+ gpio_label = gpiochip_is_requested(chip, i);
+ if (!gpio_label)
+ continue;
+ mode = at91_gpio->ops->get_periph(pio, mask);
+ seq_printf(s, "[%s] GPIO%s%d: ",
+ gpio_label, chip->label, i);
+ if (mode == AT91_MUX_GPIO) {
+ pdsr = readl_relaxed(pio + PIO_PDSR);
+
+ seq_printf(s, "[gpio] %s\n",
+ pdsr & mask ?
+ "set" : "clear");
+ } else {
+ seq_printf(s, "[periph %c]\n",
+ mode + 'A' - 1);
+ }
+ }
+}
+#else
+#define at91_gpio_dbg_show NULL
+#endif
+
+/* Several AIC controller irqs are dispatched through this GPIO handler.
+ * To use any AT91_PIN_* as an externally triggered IRQ, first call
+ * at91_set_gpio_input() then maybe enable its glitch filter.
+ * Then just request_irq() with the pin ID; it works like any ARM IRQ
+ * handler.
+ * First implementation always triggers on rising and falling edges
+ * whereas the newer PIO3 can be additionally configured to trigger on
+ * level, edge with any polarity.
+ *
+ * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
+ * configuring them with at91_set_a_periph() or at91_set_b_periph().
+ * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
+ */
+
+static void gpio_irq_mask(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << d->hwirq;
+
+ if (pio)
+ writel_relaxed(mask, pio + PIO_IDR);
+}
+
+static void gpio_irq_unmask(struct irq_data *d)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << d->hwirq;
+
+ if (pio)
+ writel_relaxed(mask, pio + PIO_IER);
+}
+
+static int gpio_irq_type(struct irq_data *d, unsigned type)
+{
+ switch (type) {
+ case IRQ_TYPE_NONE:
+ case IRQ_TYPE_EDGE_BOTH:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Alternate irq type for PIO3 support */
+static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned mask = 1 << d->hwirq;
+
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ writel_relaxed(mask, pio + PIO_ESR);
+ writel_relaxed(mask, pio + PIO_REHLSR);
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ writel_relaxed(mask, pio + PIO_ESR);
+ writel_relaxed(mask, pio + PIO_FELLSR);
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ writel_relaxed(mask, pio + PIO_LSR);
+ writel_relaxed(mask, pio + PIO_FELLSR);
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ writel_relaxed(mask, pio + PIO_LSR);
+ writel_relaxed(mask, pio + PIO_REHLSR);
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ /*
+ * disable additional interrupt modes:
+ * fall back to default behavior
+ */
+ writel_relaxed(mask, pio + PIO_AIMDR);
+ return 0;
+ case IRQ_TYPE_NONE:
+ default:
+ pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
+ return -EINVAL;
+ }
+
+ /* enable additional interrupt modes */
+ writel_relaxed(mask, pio + PIO_AIMER);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
+{
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
+ unsigned bank = at91_gpio->pioc_idx;
+
+ if (unlikely(bank >= MAX_GPIO_BANKS))
+ return -EINVAL;
+
+ irq_set_irq_wake(at91_gpio->pioc_virq, state);
+
+ return 0;
+}
+#else
+#define gpio_irq_set_wake NULL
+#endif
+
+static struct irq_chip gpio_irqchip = {
+ .name = "GPIO",
+ .irq_disable = gpio_irq_mask,
+ .irq_mask = gpio_irq_mask,
+ .irq_unmask = gpio_irq_unmask,
+ /* .irq_set_type is set dynamically */
+ .irq_set_wake = gpio_irq_set_wake,
+};
+
+static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct irq_data *idata = irq_desc_get_irq_data(desc);
+ struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
+ void __iomem *pio = at91_gpio->regbase;
+ unsigned long isr;
+ int n;
+
+ chained_irq_enter(chip, desc);
+ for (;;) {
+ /* Reading ISR acks pending (edge triggered) GPIO interrupts.
+ * When there none are pending, we're finished unless we need
+ * to process multiple banks (like ID_PIOCDE on sam9263).
+ */
+ isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR);
+ if (!isr) {
+ if (!at91_gpio->next)
+ break;
+ at91_gpio = at91_gpio->next;
+ pio = at91_gpio->regbase;
+ continue;
+ }
+
+ for_each_set_bit(n, &isr, BITS_PER_LONG) {
+ generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
+ }
+ }
+ chained_irq_exit(chip, desc);
+ /* now it may re-trigger */
+}
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key gpio_lock_class;
+
+static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct at91_gpio_chip *at91_gpio = h->host_data;
+
+ irq_set_lockdep_class(virq, &gpio_lock_class);
+
+ /*
+ * Can use the "simple" and not "edge" handler since it's
+ * shorter, and the AIC handles interrupts sanely.
+ */
+ irq_set_chip_and_handler(virq, &gpio_irqchip,
+ handle_simple_irq);
+ set_irq_flags(virq, IRQF_VALID);
+ irq_set_chip_data(virq, at91_gpio);
+
+ return 0;
+}
+
+static int at91_gpio_irq_domain_xlate(struct irq_domain *d,
+ struct device_node *ctrlr,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq,
+ unsigned int *out_type)
+{
+ struct at91_gpio_chip *at91_gpio = d->host_data;
+ int ret;
+ int pin = at91_gpio->chip.base + intspec[0];
+
+ if (WARN_ON(intsize < 2))
+ return -EINVAL;
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+
+ ret = gpio_request(pin, ctrlr->full_name);
+ if (ret)
+ return ret;
+
+ ret = gpio_direction_input(pin);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct irq_domain_ops at91_gpio_ops = {
+ .map = at91_gpio_irq_map,
+ .xlate = at91_gpio_irq_domain_xlate,
+};
+
+static int at91_gpio_of_irq_setup(struct device_node *node,
+ struct at91_gpio_chip *at91_gpio)
+{
+ struct at91_gpio_chip *prev = NULL;
+ struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
+
+ at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
+
+ /* Setup proper .irq_set_type function */
+ gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type;
+
+ /* Disable irqs of this PIO controller */
+ writel_relaxed(~0, at91_gpio->regbase + PIO_IDR);
+
+ /* Setup irq domain */
+ at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio,
+ &at91_gpio_ops, at91_gpio);
+ if (!at91_gpio->domain)
+ panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n",
+ at91_gpio->pioc_idx);
+
+ /* Setup chained handler */
+ if (at91_gpio->pioc_idx)
+ prev = gpio_chips[at91_gpio->pioc_idx - 1];
+
+ /* The toplevel handler handles one bank of GPIOs, except
+ * on some SoC it can handles up to three...
+ * We only set up the handler for the first of the list.
+ */
+ if (prev && prev->next == at91_gpio)
+ return 0;
+
+ irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio);
+ irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler);
+
+ return 0;
+}
+
+/* This structure is replicated for each GPIO block allocated at probe time */
+static struct gpio_chip at91_gpio_template = {
+ .request = at91_gpio_request,
+ .free = at91_gpio_free,
+ .direction_input = at91_gpio_direction_input,
+ .get = at91_gpio_get,
+ .direction_output = at91_gpio_direction_output,
+ .set = at91_gpio_set,
+ .to_irq = at91_gpio_to_irq,
+ .dbg_show = at91_gpio_dbg_show,
+ .can_sleep = 0,
+ .ngpio = MAX_NB_GPIO_PER_BANK,
+};
+
+static void __devinit at91_gpio_probe_fixup(void)
+{
+ unsigned i;
+ struct at91_gpio_chip *at91_gpio, *last = NULL;
+
+ for (i = 0; i < gpio_banks; i++) {
+ at91_gpio = gpio_chips[i];
+
+ /*
+ * GPIO controller are grouped on some SoC:
+ * PIOC, PIOD and PIOE can share the same IRQ line
+ */
+ if (last && last->pioc_virq == at91_gpio->pioc_virq)
+ last->next = at91_gpio;
+ last = at91_gpio;
+ }
+}
+
+static struct of_device_id at91_gpio_of_match[] __devinitdata = {
+ { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
+ { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
+ { /* sentinel */ }
+};
+
+static int __devinit at91_gpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct at91_gpio_chip *at91_chip = NULL;
+ struct gpio_chip *chip;
+ struct pinctrl_gpio_range *range;
+ int ret = 0;
+ int irq, i;
+ int alias_idx = of_alias_get_id(np, "gpio");
+ uint32_t ngpio;
+ char **names;
+
+ BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips));
+ if (gpio_chips[alias_idx]) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENOENT;
+ goto err;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto err;
+ }
+
+ at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL);
+ if (!at91_chip) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!at91_chip->regbase) {
+ dev_err(&pdev->dev, "failed to map registers, ignoring.\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ 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;
+
+ at91_chip->clock = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(at91_chip->clock)) {
+ dev_err(&pdev->dev, "failed to get clock, ignoring.\n");
+ goto err;
+ }
+
+ if (clk_prepare(at91_chip->clock))
+ goto clk_prep_err;
+
+ /* enable PIO controller's clock */
+ if (clk_enable(at91_chip->clock)) {
+ dev_err(&pdev->dev, "failed to enable clock, ignoring.\n");
+ goto clk_err;
+ }
+
+ at91_chip->chip = at91_gpio_template;
+
+ chip = &at91_chip->chip;
+ chip->of_node = np;
+ chip->label = dev_name(&pdev->dev);
+ chip->dev = &pdev->dev;
+ chip->owner = THIS_MODULE;
+ chip->base = alias_idx * MAX_NB_GPIO_PER_BANK;
+
+ if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) {
+ if (ngpio >= MAX_NB_GPIO_PER_BANK)
+ pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n",
+ alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK);
+ else
+ chip->ngpio = ngpio;
+ }
+
+ names = devm_kzalloc(&pdev->dev, sizeof(char*) * chip->ngpio, GFP_KERNEL);
+
+ if (!names) {
+ ret = -ENOMEM;
+ goto clk_err;
+ }
+
+ 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;
+
+ range = &at91_chip->range;
+ range->name = chip->label;
+ range->id = alias_idx;
+ range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK;
+
+ range->npins = chip->ngpio;
+ range->gc = chip;
+
+ ret = gpiochip_add(chip);
+ if (ret)
+ goto clk_err;
+
+ gpio_chips[alias_idx] = at91_chip;
+ gpio_banks = max(gpio_banks, alias_idx + 1);
+
+ at91_gpio_probe_fixup();
+
+ at91_gpio_of_irq_setup(np, at91_chip);
+
+ dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
+
+ return 0;
+
+clk_err:
+ clk_unprepare(at91_chip->clock);
+clk_prep_err:
+ clk_put(at91_chip->clock);
+err:
+ dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx);
+
+ return ret;
+}
+
+static struct platform_driver at91_gpio_driver = {
+ .driver = {
+ .name = "gpio-at91",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_gpio_of_match),
+ },
+ .probe = at91_gpio_probe,
+};
+
+static struct platform_driver at91_pinctrl_driver = {
+ .driver = {
+ .name = "pinctrl-at91",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_pinctrl_of_match),
+ },
+ .probe = at91_pinctrl_probe,
+ .remove = __devexit_p(at91_pinctrl_remove),
+};
+
+static int __init at91_pinctrl_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&at91_gpio_driver);
+ if (ret)
+ return ret;
+ return platform_driver_register(&at91_pinctrl_driver);
+}
+arch_initcall(at91_pinctrl_init);
+
+static void __exit at91_pinctrl_exit(void)
+{
+ platform_driver_unregister(&at91_pinctrl_driver);
+}
+
+module_exit(at91_pinctrl_exit);
+MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>");
+MODULE_DESCRIPTION("Atmel AT91 pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c
index 7e9be18ec2d2..9a963edd66d1 100644
--- a/drivers/pinctrl/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/pinctrl-bcm2835.c
@@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
-struct pinconf_ops bcm2835_pinconf_ops = {
+static 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 b446c9641212..fbb37154471c 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
+#include <linux/irqdomain.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -64,10 +65,8 @@ struct u300_gpio {
struct gpio_chip chip;
struct list_head port_list;
struct clk *clk;
- struct resource *memres;
void __iomem *base;
struct device *dev;
- int irq_base;
u32 stride;
/* Register offsets */
u32 pcr;
@@ -83,6 +82,7 @@ struct u300_gpio_port {
struct list_head node;
struct u300_gpio *gpio;
char name[8];
+ struct irq_domain *domain;
int irq;
int number;
u8 toggle_edge_mode;
@@ -314,10 +314,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct u300_gpio *gpio = to_u300_gpio(chip);
- int retirq = gpio->irq_base + offset;
+ int portno = offset >> 3;
+ struct u300_gpio_port *port = NULL;
+ struct list_head *p;
+ int retirq;
- dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset,
- retirq);
+ list_for_each(p, &gpio->port_list) {
+ port = list_entry(p, struct u300_gpio_port, node);
+ if (port->number == portno)
+ break;
+ }
+ if (port == NULL) {
+ dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n",
+ offset);
+ return -EINVAL;
+ }
+
+ /*
+ * The local hwirqs on the port are the lower three bits, there
+ * are exactly 8 IRQs per port since they are 8-bit
+ */
+ retirq = irq_find_mapping(port->domain, (offset & 0x7));
+
+ dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n",
+ offset, retirq, port->number);
return retirq;
}
@@ -467,7 +487,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
- int offset = d->irq - gpio->irq_base;
+ int offset = (port->number << 3) + d->hwirq;
u32 val;
if ((trigger & IRQF_TRIGGER_RISING) &&
@@ -503,10 +523,12 @@ static void u300_gpio_irq_enable(struct irq_data *d)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
- int offset = d->irq - gpio->irq_base;
+ int offset = (port->number << 3) + d->hwirq;
u32 val;
unsigned long flags;
+ dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n",
+ d->hwirq, port->name, offset);
local_irq_save(flags);
val = readl(U300_PIN_REG(offset, ien));
writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien));
@@ -517,7 +539,7 @@ static void u300_gpio_irq_disable(struct irq_data *d)
{
struct u300_gpio_port *port = irq_data_get_irq_chip_data(d);
struct u300_gpio *gpio = port->gpio;
- int offset = d->irq - gpio->irq_base;
+ int offset = (port->number << 3) + d->hwirq;
u32 val;
unsigned long flags;
@@ -555,8 +577,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
int irqoffset;
for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
- int pin_irq = gpio->irq_base + (port->number << 3)
- + irqoffset;
+ int pin_irq = irq_find_mapping(port->domain, irqoffset);
int offset = pinoffset + irqoffset;
dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
@@ -631,64 +652,86 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio)
list_for_each_safe(p, n, &gpio->port_list) {
port = list_entry(p, struct u300_gpio_port, node);
list_del(&port->node);
+ if (port->domain)
+ irq_domain_remove(port->domain);
kfree(port);
}
}
+/*
+ * Here we map a GPIO in the local gpio_chip pin space to a pin in
+ * the local pinctrl pin space. The pin controller used is
+ * pinctrl-u300.
+ */
+struct coh901_pinpair {
+ unsigned int offset;
+ unsigned int pin_base;
+};
+
+#define COH901_PINRANGE(a, b) { .offset = a, .pin_base = b }
+
+static struct coh901_pinpair coh901_pintable[] = {
+ COH901_PINRANGE(10, 426),
+ COH901_PINRANGE(11, 180),
+ COH901_PINRANGE(12, 165), /* MS/MMC card insertion */
+ COH901_PINRANGE(13, 179),
+ COH901_PINRANGE(14, 178),
+ COH901_PINRANGE(16, 194),
+ COH901_PINRANGE(17, 193),
+ COH901_PINRANGE(18, 192),
+ COH901_PINRANGE(19, 191),
+ COH901_PINRANGE(20, 186),
+ COH901_PINRANGE(21, 185),
+ COH901_PINRANGE(22, 184),
+ COH901_PINRANGE(23, 183),
+ COH901_PINRANGE(24, 182),
+ COH901_PINRANGE(25, 181),
+};
+
static int __init u300_gpio_probe(struct platform_device *pdev)
{
struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev);
struct u300_gpio *gpio;
+ struct resource *memres;
int err = 0;
int portno;
u32 val;
u32 ifr;
int i;
- gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL);
- if (gpio == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory\n");
+ gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL);
+ if (gpio == NULL)
return -ENOMEM;
- }
gpio->chip = u300_gpio_chip;
gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT;
- gpio->irq_base = plat->gpio_irq_base;
gpio->chip.dev = &pdev->dev;
gpio->chip.base = plat->gpio_base;
gpio->dev = &pdev->dev;
- /* Get GPIO clock */
- gpio->clk = clk_get(gpio->dev, NULL);
+ memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!memres) {
+ dev_err(gpio->dev, "could not get GPIO memory resource\n");
+ return -ENODEV;
+ }
+
+ gpio->base = devm_request_and_ioremap(&pdev->dev, memres);
+ if (!gpio->base) {
+ dev_err(gpio->dev, "could not get remap memory\n");
+ return -ENOMEM;
+ }
+
+ gpio->clk = devm_clk_get(gpio->dev, NULL);
if (IS_ERR(gpio->clk)) {
err = PTR_ERR(gpio->clk);
dev_err(gpio->dev, "could not get GPIO clock\n");
- goto err_no_clk;
+ return err;
}
+
err = clk_prepare_enable(gpio->clk);
if (err) {
dev_err(gpio->dev, "could not enable GPIO clock\n");
- goto err_no_clk_enable;
- }
-
- gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!gpio->memres) {
- dev_err(gpio->dev, "could not get GPIO memory resource\n");
- err = -ENODEV;
- goto err_no_resource;
- }
-
- if (!request_mem_region(gpio->memres->start,
- resource_size(gpio->memres),
- "GPIO Controller")) {
- err = -ENODEV;
- goto err_no_ioregion;
- }
-
- gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres));
- if (!gpio->base) {
- err = -ENOMEM;
- goto err_no_ioremap;
+ return err;
}
dev_info(gpio->dev,
@@ -732,18 +775,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
port->irq = platform_get_irq_byname(pdev,
port->name);
- dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq,
+ dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq,
port->name);
+ port->domain = irq_domain_add_linear(pdev->dev.of_node,
+ U300_GPIO_PINS_PER_PORT,
+ &irq_domain_simple_ops,
+ port);
+ if (!port->domain) {
+ err = -ENOMEM;
+ goto err_no_domain;
+ }
+
irq_set_chained_handler(port->irq, u300_gpio_irq_handler);
irq_set_handler_data(port->irq, port);
/* For each GPIO pin set the unique IRQ handler */
for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) {
- int irqno = gpio->irq_base + (portno << 3) + i;
+ int irqno = irq_create_mapping(port->domain, i);
- dev_dbg(gpio->dev, "handler for IRQ %d on %s\n",
- irqno, port->name);
+ dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n",
+ gpio->chip.base + (port->number << 3) + i,
+ port->name, irqno);
irq_set_chip_and_handler(irqno, &u300_gpio_irqchip,
handle_simple_irq);
set_irq_flags(irqno, IRQF_VALID);
@@ -763,32 +816,31 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
goto err_no_chip;
}
- /* Spawn pin controller device as child of the GPIO, pass gpio chip */
- plat->pinctrl_device->dev.platform_data = &gpio->chip;
- err = platform_device_register(plat->pinctrl_device);
- if (err)
- goto err_no_pinctrl;
+ /*
+ * Add pinctrl pin ranges, the pin controller must be registered
+ * at this point
+ */
+ for (i = 0; i < ARRAY_SIZE(coh901_pintable); i++) {
+ struct coh901_pinpair *p = &coh901_pintable[i];
+
+ err = gpiochip_add_pin_range(&gpio->chip, "pinctrl-u300",
+ p->offset, p->pin_base, 1);
+ if (err)
+ goto err_no_range;
+ }
platform_set_drvdata(pdev, gpio);
return 0;
-err_no_pinctrl:
+err_no_range:
err = gpiochip_remove(&gpio->chip);
err_no_chip:
+err_no_domain:
err_no_port:
u300_gpio_free_ports(gpio);
- iounmap(gpio->base);
-err_no_ioremap:
- release_mem_region(gpio->memres->start, resource_size(gpio->memres));
-err_no_ioregion:
-err_no_resource:
clk_disable_unprepare(gpio->clk);
-err_no_clk_enable:
- clk_put(gpio->clk);
-err_no_clk:
- kfree(gpio);
- dev_info(&pdev->dev, "module ERROR:%d\n", err);
+ dev_err(&pdev->dev, "module ERROR:%d\n", err);
return err;
}
@@ -806,13 +858,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
return err;
}
u300_gpio_free_ports(gpio);
- iounmap(gpio->base);
- release_mem_region(gpio->memres->start,
- resource_size(gpio->memres));
clk_disable_unprepare(gpio->clk);
- clk_put(gpio->clk);
platform_set_drvdata(pdev, NULL);
- kfree(gpio);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index 21362f48d370..6ff665209a4c 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -36,6 +36,7 @@
/* list of external wakeup controllers supported */
static const struct of_device_id exynos_wkup_irq_ids[] = {
{ .compatible = "samsung,exynos4210-wakeup-eint", },
+ { }
};
static void exynos_gpio_irq_unmask(struct irq_data *irqd)
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index ee7305903470..8ed20e84cb02 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -322,7 +322,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev,
{
}
-struct pinconf_ops falcon_pinconf_ops = {
+static 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 63866d95357d..525a2c8644f6 100644
--- a/drivers/pinctrl/pinctrl-imx.c
+++ b/drivers/pinctrl/pinctrl-imx.c
@@ -71,7 +71,7 @@ static const struct imx_pin_reg *imx_find_pin_reg(
break;
}
- if (!pin_reg) {
+ if (i == info->npin_regs) {
dev_err(info->dev, "Pin(%s): unable to find pin reg map\n",
info->pins[pin].name);
return NULL;
@@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
}
}
-struct pinconf_ops imx_pinconf_ops = {
+static 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 07ba7682cf22..15f501d89026 100644
--- a/drivers/pinctrl/pinctrl-lantiq.c
+++ b/drivers/pinctrl/pinctrl-lantiq.c
@@ -46,8 +46,8 @@ static int ltq_get_group_pins(struct pinctrl_dev *pctrldev,
return 0;
}
-void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+static void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
{
int i;
@@ -128,10 +128,10 @@ static int ltq_pinctrl_dt_subnode_size(struct device_node *np)
return ret;
}
-int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
- struct device_node *np_config,
- struct pinctrl_map **map,
- unsigned *num_maps)
+static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
{
struct pinctrl_map *tmp;
struct device_node *np;
@@ -275,16 +275,6 @@ static int ltq_pmx_enable(struct pinctrl_dev *pctrldev,
return 0;
}
-static void ltq_pmx_disable(struct pinctrl_dev *pctrldev,
- unsigned func,
- unsigned group)
-{
- /*
- * Nothing to do here. However, pinconf_check_ops() requires this
- * callback to be defined.
- */
-}
-
static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev,
struct pinctrl_gpio_range *range,
unsigned pin)
@@ -312,7 +302,6 @@ static struct pinmux_ops ltq_pmx_ops = {
.get_function_name = ltq_pmx_func_name,
.get_function_groups = ltq_pmx_get_groups,
.enable = ltq_pmx_enable,
- .disable = ltq_pmx_disable,
.gpio_request_enable = ltq_pmx_gpio_request_enable,
};
diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c
index 4ba4636b6a4a..3e7d4d63f8bf 100644
--- a/drivers/pinctrl/pinctrl-mxs.c
+++ b/drivers/pinctrl/pinctrl-mxs.c
@@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, "0x%lx", config);
}
-struct pinconf_ops mxs_pinconf_ops = {
+static 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 debaa75b0552..7d88ae352119 100644
--- a/drivers/pinctrl/pinctrl-nomadik-db8500.c
+++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c
@@ -475,8 +475,10 @@ static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9,
DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 };
static const unsigned hsit_a_2_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9,
DB8500_PIN_AG9, DB8500_PIN_AG8 };
-static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 };
-static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+static const unsigned clkout1_a_1_pins[] = { DB8500_PIN_AH7 };
+static const unsigned clkout1_a_2_pins[] = { DB8500_PIN_AG7 };
+static const unsigned clkout2_a_1_pins[] = { DB8500_PIN_AJ6 };
+static const unsigned clkout2_a_2_pins[] = { DB8500_PIN_AF7 };
static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29,
DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26,
DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27,
@@ -592,7 +594,8 @@ static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21,
DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 };
static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 };
static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 };
-static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 };
+static const unsigned clkout1_c_1_pins[] = { DB8500_PIN_AH13 };
+static const unsigned clkout2_c_1_pins[] = { DB8500_PIN_AH12 };
static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 };
static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9,
DB8500_PIN_AG9, DB8500_PIN_AG8 };
@@ -600,14 +603,66 @@ static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 };
static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
/* Other C1 column */
+static const unsigned u2rx_oc1_1_pins[] = { DB8500_PIN_AB2 };
+static const unsigned stmape_oc1_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4,
+ DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned remap0_oc1_1_pins[] = { DB8500_PIN_E1 };
+static const unsigned remap1_oc1_1_pins[] = { DB8500_PIN_E2 };
+static const unsigned ptma9_oc1_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2,
+ DB8500_PIN_J2, DB8500_PIN_H1 };
static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned rf_oc1_1_pins[] = { DB8500_PIN_D8, DB8500_PIN_D9 };
+static const unsigned hxclk_oc1_1_pins[] = { DB8500_PIN_D16 };
+static const unsigned uartmodrx_oc1_1_pins[] = { DB8500_PIN_B17 };
+static const unsigned uartmodtx_oc1_1_pins[] = { DB8500_PIN_C16 };
+static const unsigned stmmod_oc1_1_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 };
+static const unsigned hxgpio_oc1_1_pins[] = { DB8500_PIN_D21, DB8500_PIN_D20,
+ DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22,
+ DB8500_PIN_B24, DB8500_PIN_C22 };
+static const unsigned rf_oc1_2_pins[] = { DB8500_PIN_C23, DB8500_PIN_D23 };
static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
DB8500_PIN_AH12, DB8500_PIN_AH11 };
static const unsigned spi2_oc1_2_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12,
DB8500_PIN_AH11 };
+/* Other C2 column */
+static const unsigned sbag_oc2_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_AB2,
+ DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned etmr4_oc2_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2,
+ DB8500_PIN_J2, DB8500_PIN_H1 };
+static const unsigned ptma9_oc2_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+
+/* Other C3 column */
+static const unsigned stmmod_oc3_1_pins[] = { DB8500_PIN_AB2, DB8500_PIN_W2,
+ DB8500_PIN_W3, DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned stmmod_oc3_2_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 };
+static const unsigned uartmodrx_oc3_1_pins[] = { DB8500_PIN_H2 };
+static const unsigned uartmodtx_oc3_1_pins[] = { DB8500_PIN_J2 };
+static const unsigned etmr4_oc3_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+
+/* Other C4 column */
+static const unsigned sbag_oc4_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H1 };
+static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ 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, \
.npins = ARRAY_SIZE(a##_pins), .altsetting = b }
@@ -639,6 +694,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(kp_a_2, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A),
@@ -647,8 +703,10 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A),
- DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
- DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A),
DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
/* Altfunction B column */
DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B),
@@ -720,15 +778,41 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C),
- DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(clkout1_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(clkout2_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C),
DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C),
/* Other alt C1 column */
+ DB8500_PIN_GROUP(u2rx_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(ptma9_oc1_1, NMK_GPIO_ALT_C1),
DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(rf_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(hxclk_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(uartmodrx_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(uartmodtx_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(stmmod_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(hxgpio_oc1_1, NMK_GPIO_ALT_C1),
+ DB8500_PIN_GROUP(rf_oc1_2, NMK_GPIO_ALT_C1),
DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1),
DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1),
+ /* Other alt C2 column */
+ DB8500_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2),
+ DB8500_PIN_GROUP(etmr4_oc2_1, NMK_GPIO_ALT_C2),
+ DB8500_PIN_GROUP(ptma9_oc2_1, NMK_GPIO_ALT_C2),
+ /* Other alt C3 column */
+ DB8500_PIN_GROUP(stmmod_oc3_1, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(stmmod_oc3_2, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(uartmodrx_oc3_1, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(uartmodtx_oc3_1, NMK_GPIO_ALT_C3),
+ DB8500_PIN_GROUP(etmr4_oc3_1, NMK_GPIO_ALT_C3),
+ /* Other alt C4 column */
+ DB8500_PIN_GROUP(sbag_oc4_1, NMK_GPIO_ALT_C4),
+ DB8500_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4),
};
/* We use this macro to define the groups applicable to a function */
@@ -742,7 +826,7 @@ DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1");
* only available on two pins in alternative function C
*/
DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1",
- "u2rxtx_c_2", "u2rxtx_c_3");
+ "u2rxtx_c_2", "u2rxtx_c_3", "u2rx_oc1_1");
DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2");
/*
* MSP0 can only be on a certain set of pins, but the TX/RX pins can be
@@ -757,7 +841,7 @@ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
"lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
-DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_a_2", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1");
DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
@@ -773,7 +857,8 @@ DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1_a_2", "mc1dir_a_1");
DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
-DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
+DB8500_FUNC_GROUPS(clkout, "clkout1_a_1", "clkout1_a_2", "clkout1_c_1",
+ "clkout2_a_1", "clkout2_a_2", "clkout2_c_1");
DB8500_FUNC_GROUPS(usb, "usb_a_1");
DB8500_FUNC_GROUPS(trig, "trig_b_1");
DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1");
@@ -784,8 +869,10 @@ DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2");
* so select one of each.
*/
DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2",
- "uartmodrx_c_1", "uartmod_tx_c_1");
-DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1");
+ "uartmodrx_c_1", "uartmod_tx_c_1", "uartmodrx_oc1_1",
+ "uartmodtx_oc1_1", "uartmodrx_oc3_1", "uartmodtx_oc3_1");
+DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1", "stmmod_oc1_1",
+ "stmmod_oc3_1", "stmmod_oc3_2");
DB8500_FUNC_GROUPS(spi3, "spi3_b_1");
/* Select between CS0 on alt B or PS1 on alt C */
DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcs1_b_1", "smcleale_c_1",
@@ -799,13 +886,19 @@ DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1");
DB8500_FUNC_GROUPS(slim0, "slim0_c_1");
DB8500_FUNC_GROUPS(ms, "ms_c_1");
DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1");
-DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2");
+DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2", "stmape_oc1_1");
DB8500_FUNC_GROUPS(mc5, "mc5_c_1");
DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2");
DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2");
DB8500_FUNC_GROUPS(spi0, "spi0_c_1");
DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1", "spi2_oc1_2");
-
+DB8500_FUNC_GROUPS(remap, "remap0_oc1_1", "remap1_oc1_1");
+DB8500_FUNC_GROUPS(sbag, "sbag_oc2_1", "sbag_oc4_1");
+DB8500_FUNC_GROUPS(ptm, "ptma9_oc1_1", "ptma9_oc2_1");
+DB8500_FUNC_GROUPS(rf, "rf_oc1_1", "rf_oc1_2");
+DB8500_FUNC_GROUPS(hx, "hxclk_oc1_1", "hxgpio_oc1_1");
+DB8500_FUNC_GROUPS(etm, "etmr4_oc2_1", "etmr4_oc3_1");
+DB8500_FUNC_GROUPS(hwobs, "hwobs_oc4_1");
#define FUNCTION(fname) \
{ \
.name = #fname, \
@@ -858,6 +951,12 @@ static const struct nmk_function nmk_db8500_functions[] = {
FUNCTION(i2c3),
FUNCTION(spi0),
FUNCTION(spi2),
+ FUNCTION(remap),
+ FUNCTION(ptm),
+ FUNCTION(rf),
+ FUNCTION(hx),
+ FUNCTION(etm),
+ FUNCTION(hwobs),
};
static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = {
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c
index 52fc30181f7e..bb6a4016322a 100644
--- a/drivers/pinctrl/pinctrl-nomadik-db8540.c
+++ b/drivers/pinctrl/pinctrl-nomadik-db8540.c
@@ -460,8 +460,10 @@ static const unsigned hsit_a_1_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10,
DB8540_PIN_E10, DB8540_PIN_B12, DB8540_PIN_D10 };
static const unsigned hsit_a_2_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10,
DB8540_PIN_E10, DB8540_PIN_B12 };
-static const unsigned clkout_a_1_pins[] = { DB8540_PIN_D11, DB8540_PIN_AJ6 };
-static const unsigned clkout_a_2_pins[] = { DB8540_PIN_B13, DB8540_PIN_C12 };
+static const unsigned clkout1_a_1_pins[] = { DB8540_PIN_D11 };
+static const unsigned clkout1_a_2_pins[] = { DB8540_PIN_B13 };
+static const unsigned clkout2_a_1_pins[] = { DB8540_PIN_AJ6 };
+static const unsigned clkout2_a_2_pins[] = { DB8540_PIN_C12 };
static const unsigned msp4_a_1_pins[] = { DB8540_PIN_B14, DB8540_PIN_E11 };
static const unsigned usb_a_1_pins[] = { DB8540_PIN_D12, DB8540_PIN_D15,
DB8540_PIN_C13, DB8540_PIN_C14, DB8540_PIN_C18, DB8540_PIN_C16,
@@ -698,8 +700,10 @@ static const struct nmk_pingroup nmk_db8540_groups[] = {
DB8540_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A),
- DB8540_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
- DB8540_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A),
+ DB8540_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(msp4_a_1, NMK_GPIO_ALT_A),
DB8540_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
/* Altfunction B column */
@@ -822,6 +826,7 @@ static const struct nmk_pingroup nmk_db8540_groups[] = {
DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C4),
DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C4),
DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C4),
+ DB8540_PIN_GROUP(moduartstmmux_oc4_1, NMK_GPIO_ALT_C4),
};
@@ -830,7 +835,8 @@ static const struct nmk_pingroup nmk_db8540_groups[] = {
static const char * const a##_groups[] = { b };
DB8540_FUNC_GROUPS(apetrig, "apetrig_b_1");
-DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout_a_1", "clkout_a_2");
+DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout1_a_1", "clkout1_a_2",
+ "clkout2_a_1", "clkout2_a_2");
DB8540_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1");
DB8540_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
DB8540_FUNC_GROUPS(hwobs, "hwobs_oc4_1");
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index cf82d9ce4dee..8ef3e85cb011 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -30,26 +30,10 @@
#include <linux/pinctrl/pinconf.h>
/* Since we request GPIOs from ourself */
#include <linux/pinctrl/consumer.h>
-/*
- * For the U8500 archs, use the PRCMU register interface, for the older
- * Nomadik, provide some stubs. The functions using these will only be
- * called on the U8500 series.
- */
-#ifdef CONFIG_ARCH_U8500
-#include <linux/mfd/dbx500-prcmu.h>
-#else
-static inline u32 prcmu_read(unsigned int reg) {
- return 0;
-}
-static inline void prcmu_write(unsigned int reg, u32 value) {}
-static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
-#endif
+#include <linux/platform_data/pinctrl-nomadik.h>
#include <asm/mach/irq.h>
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
-
#include "pinctrl-nomadik.h"
/*
@@ -60,8 +44,6 @@ static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {}
* Symbols in this file are called "nmk_gpio" for "nomadik gpio"
*/
-#define NMK_GPIO_PER_CHIP 32
-
struct nmk_gpio_chip {
struct gpio_chip chip;
struct irq_domain *domain;
@@ -86,10 +68,18 @@ struct nmk_gpio_chip {
u32 lowemi;
};
+/**
+ * struct nmk_pinctrl - state container for the Nomadik pin controller
+ * @dev: containing device pointer
+ * @pctl: corresponding pin controller device
+ * @soc: SoC data for this specific chip
+ * @prcm_base: PRCM register range virtual base
+ */
struct nmk_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
const struct nmk_pinctrl_soc_data *soc;
+ void __iomem *prcm_base;
};
static struct nmk_gpio_chip *
@@ -251,6 +241,15 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
}
+static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value)
+{
+ u32 val;
+
+ val = readl(reg);
+ val = ((val & ~mask) | (value & mask));
+ writel(val, reg);
+}
+
static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
unsigned offset, unsigned alt_num)
{
@@ -289,8 +288,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
if (pin_desc->altcx[i].used == true) {
reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
bit = pin_desc->altcx[i].control_bit;
- if (prcmu_read(reg) & BIT(bit)) {
- prcmu_write_masked(reg, BIT(bit), 0);
+ if (readl(npct->prcm_base + reg) & BIT(bit)) {
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0);
dev_dbg(npct->dev,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n",
offset, i+1);
@@ -318,8 +317,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
if (pin_desc->altcx[i].used == true) {
reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
bit = pin_desc->altcx[i].control_bit;
- if (prcmu_read(reg) & BIT(bit)) {
- prcmu_write_masked(reg, BIT(bit), 0);
+ if (readl(npct->prcm_base + reg) & BIT(bit)) {
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0);
dev_dbg(npct->dev,
"PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n",
offset, i+1);
@@ -331,7 +330,7 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct,
bit = pin_desc->altcx[alt_index].control_bit;
dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n",
offset, alt_index+1);
- prcmu_write_masked(reg, BIT(bit), BIT(bit));
+ nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit));
}
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
@@ -536,7 +535,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
* and its sleep mode based on the specified configuration. The @cfg is
* usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
* are constructed using, and can be further enhanced with, the macros in
- * plat/pincfg.h.
+ * <linux/platform_data/pinctrl-nomadik.h>
*
* If a pin's mode is set to GPIO, it is configured as an input to avoid
* side-effects. The gpio can be manipulated later using standard GPIO API
@@ -675,6 +674,35 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
}
EXPORT_SYMBOL(nmk_gpio_set_mode);
+static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
+{
+ int i;
+ u16 reg;
+ u8 bit;
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct prcm_gpiocr_altcx_pin_desc *pin_desc;
+ const u16 *gpiocr_regs;
+
+ for (i = 0; i < npct->soc->npins_altcx; i++) {
+ if (npct->soc->altcx_pins[i].pin == gpio)
+ break;
+ }
+ if (i == npct->soc->npins_altcx)
+ return NMK_GPIO_ALT_C;
+
+ pin_desc = npct->soc->altcx_pins + i;
+ gpiocr_regs = npct->soc->prcm_gpiocr_registers;
+ for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) {
+ if (pin_desc->altcx[i].used == true) {
+ reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
+ bit = pin_desc->altcx[i].control_bit;
+ if (readl(npct->prcm_base + reg) & BIT(bit))
+ return NMK_GPIO_ALT_C+i+1;
+ }
+ }
+ return NMK_GPIO_ALT_C;
+}
+
int nmk_gpio_get_mode(int gpio)
{
struct nmk_gpio_chip *nmk_chip;
@@ -1063,8 +1091,9 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
#include <linux/seq_file.h>
-static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
- unsigned offset, unsigned gpio)
+static void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
{
const char *label = gpiochip_is_requested(chip, offset);
struct nmk_gpio_chip *nmk_chip =
@@ -1078,12 +1107,18 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
[NMK_GPIO_ALT_A] = "altA",
[NMK_GPIO_ALT_B] = "altB",
[NMK_GPIO_ALT_C] = "altC",
+ [NMK_GPIO_ALT_C+1] = "altC1",
+ [NMK_GPIO_ALT_C+2] = "altC2",
+ [NMK_GPIO_ALT_C+3] = "altC3",
+ [NMK_GPIO_ALT_C+4] = "altC4",
};
clk_enable(nmk_chip->clk);
is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
mode = nmk_gpio_get_mode(gpio);
+ if ((mode == NMK_GPIO_ALT_C) && pctldev)
+ mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
gpio, label ?: "(none)",
@@ -1127,13 +1162,14 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
unsigned gpio = chip->base;
for (i = 0; i < chip->ngpio; i++, gpio++) {
- nmk_gpio_dbg_show_one(s, chip, i, gpio);
+ nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio);
seq_printf(s, "\n");
}
}
#else
static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
struct gpio_chip *chip,
unsigned offset, unsigned gpio)
{
@@ -1250,8 +1286,8 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
}
}
-int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct nmk_gpio_chip *nmk_chip = d->host_data;
@@ -1464,7 +1500,7 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
return;
}
chip = range->gc;
- nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+ nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset);
}
static struct pinctrl_ops nmk_pinctrl_ops = {
@@ -1635,9 +1671,9 @@ static void nmk_pmx_disable(struct pinctrl_dev *pctldev,
dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins);
}
-int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset)
+static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
{
struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
struct nmk_gpio_chip *nmk_chip;
@@ -1666,9 +1702,9 @@ int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
return 0;
}
-void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset)
+static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
{
struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
@@ -1686,17 +1722,15 @@ static struct pinmux_ops nmk_pinmux_ops = {
.gpio_disable_free = nmk_gpio_disable_free,
};
-int nmk_pin_config_get(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long *config)
+static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
{
/* Not implemented */
return -EINVAL;
}
-int nmk_pin_config_set(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long config)
+static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config)
{
static const char *pullnames[] = {
[NMK_GPIO_PULL_NONE] = "none",
@@ -1818,6 +1852,7 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
const struct platform_device_id *platid = platform_get_device_id(pdev);
struct device_node *np = pdev->dev.of_node;
struct nmk_pinctrl *npct;
+ struct resource *res;
unsigned int version = 0;
int i;
@@ -1827,9 +1862,14 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
if (platid)
version = platid->driver_data;
- else if (np)
- version = (unsigned int)
- of_match_device(nmk_pinctrl_match, &pdev->dev)->data;
+ else if (np) {
+ const struct of_device_id *match;
+
+ match = of_match_device(nmk_pinctrl_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
+ version = (unsigned int) match->data;
+ }
/* Poke in other ASIC variants here */
if (version == PINCTRL_NMK_STN8815)
@@ -1839,22 +1879,37 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
if (version == PINCTRL_NMK_DB8540)
nmk_pinctrl_db8540_init(&npct->soc);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ npct->prcm_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!npct->prcm_base) {
+ dev_err(&pdev->dev,
+ "failed to ioremap PRCM registers\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_info(&pdev->dev,
+ "No PRCM base, assume no ALT-Cx control is available\n");
+ }
+
/*
* We need all the GPIO drivers to probe FIRST, or we will not be able
* to obtain references to the struct gpio_chip * for them, and we
* need this to proceed.
*/
for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
- if (!nmk_gpio_chips[i]) {
+ if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) {
dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
return -EPROBE_DEFER;
}
- npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
+ npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip;
}
nmk_pinctrl_desc.pins = npct->soc->pins;
nmk_pinctrl_desc.npins = npct->soc->npins;
npct->dev = &pdev->dev;
+
npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
if (!npct->pctl) {
dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
@@ -1889,6 +1944,7 @@ static const struct platform_device_id nmk_pinctrl_id[] = {
{ "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
{ "pinctrl-db8500", PINCTRL_NMK_DB8500 },
{ "pinctrl-db8540", PINCTRL_NMK_DB8540 },
+ { }
};
static struct platform_driver nmk_pinctrl_driver = {
diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h
index eef316e979a0..bcd4191e10ea 100644
--- a/drivers/pinctrl/pinctrl-nomadik.h
+++ b/drivers/pinctrl/pinctrl-nomadik.h
@@ -1,7 +1,7 @@
#ifndef PINCTRL_PINCTRL_NOMADIK_H
#define PINCTRL_PINCTRL_NOMADIK_H
-#include <plat/gpio-nomadik.h>
+#include <linux/platform_data/pinctrl-nomadik.h>
/* Package definitions */
#define PINCTRL_NMK_STN8815 0
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c
index f14cd6ba4c0b..51f8a388b917 100644
--- a/drivers/pinctrl/pinctrl-pxa3xx.c
+++ b/drivers/pinctrl/pinctrl-pxa3xx.c
@@ -173,7 +173,6 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev,
{
struct pinctrl_desc *desc;
struct resource *res;
- int ret = 0;
if (!info || !info->cputype)
return -EINVAL;
@@ -188,23 +187,17 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev,
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
- info->phy_base = res->start;
- info->phy_size = resource_size(res);
- info->virt_base = ioremap(info->phy_base, info->phy_size);
+ info->virt_base = devm_request_and_ioremap(&pdev->dev, res);
if (!info->virt_base)
return -ENOMEM;
info->pctrl = pinctrl_register(desc, &pdev->dev, info);
if (!info->pctrl) {
dev_err(&pdev->dev, "failed to register PXA pinmux driver\n");
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range);
platform_set_drvdata(pdev, info);
return 0;
-err:
- iounmap(info->virt_base);
- return ret;
}
int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
@@ -212,7 +205,6 @@ int pxa3xx_pinctrl_unregister(struct platform_device *pdev)
struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev);
pinctrl_unregister(info->pctrl);
- iounmap(info->virt_base);
platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h
index 8135744d6599..92fad0880834 100644
--- a/drivers/pinctrl/pinctrl-pxa3xx.h
+++ b/drivers/pinctrl/pinctrl-pxa3xx.h
@@ -60,8 +60,6 @@ struct pxa3xx_pinmux_info {
struct device *dev;
struct pinctrl_dev *pctrl;
enum pxa_cpu_type cputype;
- unsigned int phy_base;
- unsigned int phy_size;
void __iomem *virt_base;
struct pxa3xx_mfp_pin *mfp;
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 726a729a2ec9..554946356fba 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -30,6 +30,7 @@
#define PCS_MUX_BITS_NAME "pinctrl-single,bits"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_OFF_DISABLED ~0U
+#define PCS_MAX_GPIO_VALUES 2
/**
* struct pcs_pingroup - pingroups for a function
@@ -77,6 +78,16 @@ struct pcs_function {
};
/**
+ * struct pcs_gpio_range - pinctrl gpio range
+ * @range: subrange of the GPIO number space
+ * @gpio_func: gpio function value in the pinmux register
+ */
+struct pcs_gpio_range {
+ struct pinctrl_gpio_range range;
+ int gpio_func;
+};
+
+/**
* struct pcs_data - wrapper for data needed by pinctrl framework
* @pa: pindesc array
* @cur: index to current element
@@ -244,15 +255,15 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
- unsigned offset)
+ unsigned pin)
{
struct pcs_device *pcs;
- unsigned val;
+ unsigned val, mux_bytes;
pcs = pinctrl_dev_get_drvdata(pctldev);
- val = pcs->read(pcs->base + offset);
- val &= pcs->fmask;
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ val = pcs->read(pcs->base + pin * mux_bytes);
seq_printf(s, "%08x %s " , val, DRIVER_NAME);
}
@@ -403,9 +414,26 @@ 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_gpio_range *gpio = NULL;
+ int end, mux_bytes;
+ unsigned data;
+
+ gpio = container_of(range, struct pcs_gpio_range, range);
+ end = range->pin_base + range->npins - 1;
+ if (pin < range->pin_base || pin > end) {
+ dev_err(pctldev->dev,
+ "pin %d isn't in the range of %d to %d\n",
+ pin, range->pin_base, end);
+ return -EINVAL;
+ }
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+ data |= gpio->gpio_func;
+ pcs->write(data, pcs->base + pin * mux_bytes);
+ return 0;
}
static struct pinmux_ops pcs_pinmux_ops = {
@@ -772,7 +800,7 @@ 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);
- if (!map)
+ if (!*map)
return -ENOMEM;
*num_maps = 0;
@@ -879,6 +907,50 @@ static void pcs_free_resources(struct pcs_device *pcs)
static struct of_device_id pcs_of_match[];
+static int __devinit pcs_add_gpio_range(struct device_node *node,
+ struct pcs_device *pcs)
+{
+ struct pcs_gpio_range *gpio;
+ struct device_node *child;
+ struct resource r;
+ const char name[] = "pinctrl-single";
+ u32 gpiores[PCS_MAX_GPIO_VALUES];
+ int ret, i = 0, mux_bytes = 0;
+
+ for_each_child_of_node(node, child) {
+ ret = of_address_to_resource(child, 0, &r);
+ if (ret < 0)
+ continue;
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32_array(child, "pinctrl-single,gpio",
+ gpiores, PCS_MAX_GPIO_VALUES);
+ if (ret < 0)
+ continue;
+ gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio) {
+ dev_err(pcs->dev, "failed to allocate pcs gpio\n");
+ return -ENOMEM;
+ }
+ gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name),
+ GFP_KERNEL);
+ if (!gpio->range.name) {
+ dev_err(pcs->dev, "failed to allocate range name\n");
+ return -ENOMEM;
+ }
+ memcpy((char *)gpio->range.name, name, sizeof(name));
+
+ gpio->range.id = i++;
+ gpio->range.base = gpiores[0];
+ gpio->gpio_func = gpiores[1];
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes;
+ gpio->range.npins = (r.end - r.start) / mux_bytes + 1;
+
+ pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
+ }
+ return 0;
+}
+
static int __devinit pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -975,6 +1047,10 @@ static int __devinit pcs_probe(struct platform_device *pdev)
goto free;
}
+ ret = pcs_add_gpio_range(np, pcs);
+ if (ret < 0)
+ goto free;
+
dev_info(pcs->dev, "%i pins at pa %p size %u\n",
pcs->desc.npins, pcs->base, pcs->size);
diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c
index 9ecacf3d0a75..a3905e58d1b3 100644
--- a/drivers/pinctrl/pinctrl-sirf.c
+++ b/drivers/pinctrl/pinctrl-sirf.c
@@ -32,10 +32,10 @@
#define SIRFSOC_NUM_PADS 622
#define SIRFSOC_RSC_PIN_MUX 0x4
-#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
+#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90)
#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4)
#define SIRFSOC_GPIO_DSP_EN0 (0x80)
-#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C)
#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1
@@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank {
int id;
int parent_irq;
spinlock_t lock;
+ bool is_marco; /* for marco, some registers are different with prima2 */
};
static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
@@ -191,6 +192,7 @@ struct sirfsoc_pmx {
struct pinctrl_dev *pmx;
void __iomem *gpio_virtbase;
void __iomem *rsc_virtbase;
+ bool is_marco;
};
/* SIRFSOC_GPIO_PAD_EN set */
@@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector
for (i = 0; i < mux->muxmask_counts; i++) {
u32 muxval;
- muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
- if (enable)
- muxval = muxval & ~mask[i].mask;
- else
- muxval = muxval | mask[i].mask;
- writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ if (!spmx->is_marco) {
+ muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ if (enable)
+ muxval = muxval & ~mask[i].mask;
+ else
+ muxval = muxval | mask[i].mask;
+ writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ } else {
+ if (enable)
+ writel(mask[i].mask, spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
+ else
+ writel(mask[i].mask, spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ }
}
if (mux->funcmask && enable) {
@@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
spmx = pinctrl_dev_get_drvdata(pmxdev);
- muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
- muxval = muxval | (1 << (offset - range->pin_base));
- writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ if (!spmx->is_marco) {
+ muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ muxval = muxval | (1 << (offset - range->pin_base));
+ writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
+ } else {
+ writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(group));
+ }
return 0;
}
@@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
{
const struct of_device_id rsc_ids[] = {
{ .compatible = "sirf,prima2-rsc" },
+ { .compatible = "sirf,marco-rsc" },
{}
};
struct device_node *np;
@@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev)
goto out_no_rsc_remap;
}
+ if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+ spmx->is_marco = 1;
+
/* Now register the pin controller and all pins it handles */
spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
if (!spmx->pmx) {
@@ -1287,6 +1307,7 @@ out_no_gpio_remap:
static const struct of_device_id pinmux_ids[] __devinitconst = {
{ .compatible = "sirf,prima2-pinctrl" },
+ { .compatible = "sirf,marco-pinctrl" },
{}
};
@@ -1621,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
spin_unlock_irqrestore(&bank->lock, flags);
}
-int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
struct sirfsoc_gpio_bank *bank = d->host_data;
@@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
struct sirfsoc_gpio_bank *bank;
void *regs;
struct platform_device *pdev;
+ bool is_marco = false;
pdev = of_find_device_by_node(np);
if (!pdev)
@@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
if (!regs)
return -ENOMEM;
+ if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
+ is_marco = 1;
+
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
bank = &sgpio_bank[i];
spin_lock_init(&bank->lock);
@@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np)
bank->chip.gc.of_node = np;
bank->chip.regs = regs;
bank->id = i;
+ bank->is_marco = is_marco;
bank->parent_irq = platform_get_irq(pdev, i);
if (bank->parent_irq < 0) {
err = bank->parent_irq;
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 7da0b371fd65..e9f80a54b3d0 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -178,8 +178,9 @@ static int add_config(struct device *dev, unsigned long **configs,
return 0;
}
-void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+static void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map,
+ unsigned num_maps)
{
int i;
@@ -209,11 +210,11 @@ static const struct cfg_param {
{"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
};
-int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
- struct device_node *np,
- struct pinctrl_map **map,
- unsigned *reserved_maps,
- unsigned *num_maps)
+static int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserved_maps,
+ unsigned *num_maps)
{
int ret, i;
const char *function;
@@ -288,9 +289,10 @@ exit:
return ret;
}
-int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
- struct device_node *np_config,
- struct pinctrl_map **map, unsigned *num_maps)
+static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
{
unsigned reserved_maps;
struct device_node *np;
@@ -660,7 +662,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
}
#endif
-struct pinconf_ops tegra_pinconf_ops = {
+static 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 309f5b9a70ec..b84de03ed54d 100644
--- a/drivers/pinctrl/pinctrl-u300.c
+++ b/drivers/pinctrl/pinctrl-u300.c
@@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = {
struct u300_pmx {
struct device *dev;
struct pinctrl_dev *pctl;
- u32 phybase;
- u32 physize;
void __iomem *virtbase;
};
@@ -1013,52 +1011,11 @@ static struct pinmux_ops u300_pmx_ops = {
.disable = u300_pmx_disable,
};
-/*
- * GPIO ranges handled by the application-side COH901XXX GPIO controller
- * Very many pins can be converted into GPIO pins, but we only list those
- * that are useful in practice to cut down on tables.
- */
-#define U300_GPIO_RANGE(a, b, c) { .name = "COH901XXX", .id = a, .base= a, \
- .pin_base = b, .npins = c }
-
-static struct pinctrl_gpio_range u300_gpio_ranges[] = {
- U300_GPIO_RANGE(10, 426, 1),
- U300_GPIO_RANGE(11, 180, 1),
- U300_GPIO_RANGE(12, 165, 1), /* MS/MMC card insertion */
- U300_GPIO_RANGE(13, 179, 1),
- U300_GPIO_RANGE(14, 178, 1),
- U300_GPIO_RANGE(16, 194, 1),
- U300_GPIO_RANGE(17, 193, 1),
- U300_GPIO_RANGE(18, 192, 1),
- U300_GPIO_RANGE(19, 191, 1),
- U300_GPIO_RANGE(20, 186, 1),
- U300_GPIO_RANGE(21, 185, 1),
- U300_GPIO_RANGE(22, 184, 1),
- U300_GPIO_RANGE(23, 183, 1),
- U300_GPIO_RANGE(24, 182, 1),
- U300_GPIO_RANGE(25, 181, 1),
-};
-
-static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
- struct pinctrl_gpio_range *range;
-
- range = &u300_gpio_ranges[i];
- if (pin >= range->pin_base &&
- pin <= (range->pin_base + range->npins - 1))
- return range;
- }
- return NULL;
-}
-
-int u300_pin_config_get(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long *config)
+static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
{
- struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+ struct pinctrl_gpio_range *range =
+ pinctrl_find_gpio_range_from_pin(pctldev, pin);
/* We get config for those pins we CAN get it for and that's it */
if (!range)
@@ -1069,11 +1026,11 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev,
config);
}
-int u300_pin_config_set(struct pinctrl_dev *pctldev,
- unsigned pin,
- unsigned long config)
+static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config)
{
- struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+ struct pinctrl_gpio_range *range =
+ pinctrl_find_gpio_range_from_pin(pctldev, pin);
int ret;
if (!range)
@@ -1109,9 +1066,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
{
struct u300_pmx *upmx;
struct resource *res;
- struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev);
- int ret;
- int i;
/* Create state holders etc for this driver */
upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL);
@@ -1123,32 +1077,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOENT;
- upmx->phybase = res->start;
- upmx->physize = resource_size(res);
-
- if (request_mem_region(upmx->phybase, upmx->physize,
- DRIVER_NAME) == NULL) {
- ret = -ENOMEM;
- goto out_no_memregion;
- }
- upmx->virtbase = ioremap(upmx->phybase, upmx->physize);
- if (!upmx->virtbase) {
- ret = -ENOMEM;
- goto out_no_remap;
- }
+ upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res);
+ if (!upmx->virtbase)
+ return -ENOMEM;
upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
if (!upmx->pctl) {
dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
- ret = -EINVAL;
- goto out_no_pmx;
- }
-
- /* We will handle a range of GPIO pins */
- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
- u300_gpio_ranges[i].gc = gpio_chip;
- pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
+ return -EINVAL;
}
platform_set_drvdata(pdev, upmx);
@@ -1156,14 +1093,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "initialized U300 pin control driver\n");
return 0;
-
-out_no_pmx:
- iounmap(upmx->virtbase);
-out_no_remap:
- platform_set_drvdata(pdev, NULL);
-out_no_memregion:
- release_mem_region(upmx->phybase, upmx->physize);
- return ret;
}
static int __devexit u300_pmx_remove(struct platform_device *pdev)
@@ -1171,8 +1100,6 @@ static int __devexit u300_pmx_remove(struct platform_device *pdev)
struct u300_pmx *upmx = platform_get_drvdata(pdev);
pinctrl_unregister(upmx->pctl);
- iounmap(upmx->virtbase);
- release_mem_region(upmx->phybase, upmx->physize);
platform_set_drvdata(pdev, NULL);
return 0;
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index b9bcaec66223..ad90984ec500 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -522,7 +522,7 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev,
return 0;
}
-struct pinconf_ops xway_pinconf_ops = {
+static struct pinconf_ops xway_pinconf_ops = {
.pin_config_get = xway_pinconf_get,
.pin_config_set = xway_pinconf_set,
};
diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c
index 9301a7a95eff..1a00658b3ea0 100644
--- a/drivers/pinctrl/pinmux.c
+++ b/drivers/pinctrl/pinmux.c
@@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
{
struct pinctrl_dev *pctldev = setting->pctldev;
const struct pinmux_ops *pmxops = pctldev->desc->pmxops;
- const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
char const * const *groups;
unsigned num_groups;
int ret;
const char *group;
int i;
- const unsigned *pins;
- unsigned num_pins;
if (!pmxops) {
dev_err(pctldev->dev, "does not support mux function\n");
@@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map,
}
setting->data.mux.group = ret;
- ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins,
- &num_pins);
- if (ret) {
- dev_err(pctldev->dev,
- "could not get pins for device %s group selector %d\n",
- pinctrl_dev_get_name(pctldev), setting->data.mux.group);
- return -ENODEV;
- }
-
- /* Try to allocate all pins in this group, one by one */
- for (i = 0; i < num_pins; i++) {
- ret = pin_request(pctldev, pins[i], map->dev_name, NULL);
- if (ret) {
- dev_err(pctldev->dev,
- "could not request pin %d on device %s\n",
- pins[i], pinctrl_dev_get_name(pctldev));
- /* On error release all taken pins */
- i--; /* this pin just failed */
- for (; i >= 0; i--)
- pin_free(pctldev, pins[i], NULL);
- return -ENODEV;
- }
- }
-
return 0;
}
void pinmux_free_setting(struct pinctrl_setting const *setting)
{
- struct pinctrl_dev *pctldev = setting->pctldev;
- const struct pinctrl_ops *pctlops = pctldev->desc->pctlops;
- const unsigned *pins;
- unsigned num_pins;
- int ret;
- int i;
-
- ret = pctlops->get_group_pins(pctldev, setting->data.mux.group,
- &pins, &num_pins);
- if (ret) {
- dev_err(pctldev->dev,
- "could not get pins for device %s group selector %d\n",
- pinctrl_dev_get_name(pctldev), setting->data.mux.group);
- return;
- }
-
- for (i = 0; i < num_pins; i++)
- pin_free(pctldev, pins[i], NULL);
+ /* This function is currently unused */
}
int pinmux_enable_setting(struct pinctrl_setting const *setting)
@@ -446,6 +402,18 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting)
num_pins = 0;
}
+ /* Try to allocate all pins in this group, one by one */
+ for (i = 0; i < num_pins; i++) {
+ ret = pin_request(pctldev, pins[i], setting->dev_name, NULL);
+ if (ret) {
+ dev_err(pctldev->dev,
+ "could not request pin %d on device %s\n",
+ pins[i], pinctrl_dev_get_name(pctldev));
+ goto err_pin_request;
+ }
+ }
+
+ /* Now that we have acquired the pins, encode the mux setting */
for (i = 0; i < num_pins; i++) {
desc = pin_desc_get(pctldev, pins[i]);
if (desc == NULL) {
@@ -457,8 +425,26 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting)
desc->mux_setting = &(setting->data.mux);
}
- return ops->enable(pctldev, setting->data.mux.func,
- setting->data.mux.group);
+ ret = ops->enable(pctldev, setting->data.mux.func,
+ setting->data.mux.group);
+
+ if (ret)
+ goto err_enable;
+
+ return 0;
+
+err_enable:
+ for (i = 0; i < num_pins; i++) {
+ desc = pin_desc_get(pctldev, pins[i]);
+ if (desc)
+ desc->mux_setting = NULL;
+ }
+err_pin_request:
+ /* On error release all taken pins */
+ while (--i >= 0)
+ pin_free(pctldev, pins[i], NULL);
+
+ return ret;
}
void pinmux_disable_setting(struct pinctrl_setting const *setting)
@@ -482,6 +468,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
num_pins = 0;
}
+ /* Flag the descs that no setting is active */
for (i = 0; i < num_pins; i++) {
desc = pin_desc_get(pctldev, pins[i]);
if (desc == NULL) {
@@ -493,6 +480,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting)
desc->mux_setting = NULL;
}
+ /* And release the pins */
+ for (i = 0; i < num_pins; i++)
+ pin_free(pctldev, pins[i], NULL);
+
if (ops->disable)
ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group);
}
diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig
index 91558791e766..04d93e602674 100644
--- a/drivers/pinctrl/spear/Kconfig
+++ b/drivers/pinctrl/spear/Kconfig
@@ -25,20 +25,31 @@ config PINCTRL_SPEAR310
bool "ST Microelectronics SPEAr310 SoC pin controller driver"
depends on MACH_SPEAR310
select PINCTRL_SPEAR3XX
+ select PINCTRL_SPEAR_PLGPIO
config PINCTRL_SPEAR320
bool "ST Microelectronics SPEAr320 SoC pin controller driver"
depends on MACH_SPEAR320
select PINCTRL_SPEAR3XX
+ select PINCTRL_SPEAR_PLGPIO
config PINCTRL_SPEAR1310
bool "ST Microelectronics SPEAr1310 SoC pin controller driver"
depends on MACH_SPEAR1310
select PINCTRL_SPEAR
+ select PINCTRL_SPEAR_PLGPIO
config PINCTRL_SPEAR1340
bool "ST Microelectronics SPEAr1340 SoC pin controller driver"
depends on MACH_SPEAR1340
select PINCTRL_SPEAR
+ select PINCTRL_SPEAR_PLGPIO
+
+config PINCTRL_SPEAR_PLGPIO
+ bool "SPEAr SoC PLGPIO Controller"
+ depends on GPIOLIB && PINCTRL_SPEAR
+ help
+ Say yes here to support PLGPIO controller on ST Microelectronics SPEAr
+ SoCs.
endif
diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile
index b28a7ba22443..0e400ebeb8ff 100644
--- a/drivers/pinctrl/spear/Makefile
+++ b/drivers/pinctrl/spear/Makefile
@@ -1,5 +1,6 @@
# SPEAr pinmux support
+obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o
obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o
obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
new file mode 100644
index 000000000000..4c045053bbdd
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -0,0 +1,758 @@
+/*
+ * SPEAr platform PLGPIO driver
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@linaro.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/spinlock.h>
+#include <asm/mach/irq.h>
+
+#define MAX_GPIO_PER_REG 32
+#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG)
+#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \
+ * sizeof(int *))
+
+/*
+ * plgpio pins in all machines are not one to one mapped, bitwise with registers
+ * bits. These set of macros define register masks for which below functions
+ * (pin_to_offset and offset_to_pin) are required to be called.
+ */
+#define PTO_ENB_REG 0x001
+#define PTO_WDATA_REG 0x002
+#define PTO_DIR_REG 0x004
+#define PTO_IE_REG 0x008
+#define PTO_RDATA_REG 0x010
+#define PTO_MIS_REG 0x020
+
+struct plgpio_regs {
+ u32 enb; /* enable register */
+ u32 wdata; /* write data register */
+ u32 dir; /* direction set register */
+ u32 rdata; /* read data register */
+ u32 ie; /* interrupt enable register */
+ u32 mis; /* mask interrupt status register */
+ u32 eit; /* edge interrupt type */
+};
+
+/*
+ * struct plgpio: plgpio driver specific structure
+ *
+ * lock: lock for guarding gpio registers
+ * base: base address of plgpio block
+ * irq_base: irq number of plgpio0
+ * chip: gpio framework specific chip information structure
+ * p2o: function ptr for pin to offset conversion. This is required only for
+ * machines where mapping b/w pin and offset is not 1-to-1.
+ * o2p: function ptr for offset to pin conversion. This is required only for
+ * machines where mapping b/w pin and offset is not 1-to-1.
+ * p2o_regs: mask of registers for which p2o and o2p are applicable
+ * regs: register offsets
+ * csave_regs: context save registers for standby/sleep/hibernate cases
+ */
+struct plgpio {
+ spinlock_t lock;
+ void __iomem *base;
+ struct clk *clk;
+ unsigned irq_base;
+ struct irq_domain *irq_domain;
+ struct gpio_chip chip;
+ int (*p2o)(int pin); /* pin_to_offset */
+ int (*o2p)(int offset); /* offset_to_pin */
+ u32 p2o_regs;
+ struct plgpio_regs regs;
+#ifdef CONFIG_PM
+ struct plgpio_regs *csave_regs;
+#endif
+};
+
+/* register manipulation inline functions */
+static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg)
+{
+ u32 offset = PIN_OFFSET(pin);
+ void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+ u32 val = readl_relaxed(reg_off);
+
+ return !!(val & (1 << offset));
+}
+
+static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg)
+{
+ u32 offset = PIN_OFFSET(pin);
+ void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+ u32 val = readl_relaxed(reg_off);
+
+ writel_relaxed(val | (1 << offset), reg_off);
+}
+
+static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg)
+{
+ u32 offset = PIN_OFFSET(pin);
+ void __iomem *reg_off = REG_OFFSET(base, reg, pin);
+ u32 val = readl_relaxed(reg_off);
+
+ writel_relaxed(val & ~(1 << offset), reg_off);
+}
+
+/* gpio framework specific routines */
+static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ unsigned long flags;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+
+ return 0;
+}
+
+static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ unsigned long flags;
+ unsigned dir_offset = offset, wdata_offset = offset, tmp;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) {
+ tmp = plgpio->p2o(offset);
+ if (tmp == -1)
+ return -EINVAL;
+
+ if (plgpio->p2o_regs & PTO_DIR_REG)
+ dir_offset = tmp;
+ if (plgpio->p2o_regs & PTO_WDATA_REG)
+ wdata_offset = tmp;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ if (value)
+ plgpio_reg_set(plgpio->base, wdata_offset,
+ plgpio->regs.wdata);
+ else
+ plgpio_reg_reset(plgpio->base, wdata_offset,
+ plgpio->regs.wdata);
+
+ plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+
+ return 0;
+}
+
+static int plgpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return -EINVAL;
+ }
+
+ return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata);
+}
+
+static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+ if (offset >= chip->ngpio)
+ return;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ if (value)
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata);
+ else
+ plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata);
+}
+
+static int plgpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ int gpio = chip->base + offset;
+ unsigned long flags;
+ int ret = 0;
+
+ if (offset >= chip->ngpio)
+ return -EINVAL;
+
+ ret = pinctrl_request_gpio(gpio);
+ if (ret)
+ return ret;
+
+ if (!IS_ERR(plgpio->clk)) {
+ ret = clk_enable(plgpio->clk);
+ if (ret)
+ goto err0;
+ }
+
+ if (plgpio->regs.enb == -1)
+ return 0;
+
+ /*
+ * put gpio in IN mode before enabling it. This make enabling gpio safe
+ */
+ ret = plgpio_direction_input(chip, offset);
+ if (ret)
+ goto err1;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1) {
+ ret = -EINVAL;
+ goto err1;
+ }
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+ return 0;
+
+err1:
+ if (!IS_ERR(plgpio->clk))
+ clk_disable(plgpio->clk);
+err0:
+ pinctrl_free_gpio(gpio);
+ return ret;
+}
+
+static void plgpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+ int gpio = chip->base + offset;
+ unsigned long flags;
+
+ if (offset >= chip->ngpio)
+ return;
+
+ if (plgpio->regs.enb == -1)
+ goto disable_clk;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+
+disable_clk:
+ if (!IS_ERR(plgpio->clk))
+ clk_disable(plgpio->clk);
+
+ pinctrl_free_gpio(gpio);
+}
+
+static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct plgpio *plgpio = container_of(chip, struct plgpio, chip);
+
+ if (IS_ERR_VALUE(plgpio->irq_base))
+ return -EINVAL;
+
+ return irq_find_mapping(plgpio->irq_domain, offset);
+}
+
+/* PLGPIO IRQ */
+static void plgpio_irq_disable(struct irq_data *d)
+{
+ struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - plgpio->irq_base;
+ unsigned long flags;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+}
+
+static void plgpio_irq_enable(struct irq_data *d)
+{
+ struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - plgpio->irq_base;
+ unsigned long flags;
+
+ /* get correct offset for "offset" pin */
+ if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) {
+ offset = plgpio->p2o(offset);
+ if (offset == -1)
+ return;
+ }
+
+ spin_lock_irqsave(&plgpio->lock, flags);
+ plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie);
+ spin_unlock_irqrestore(&plgpio->lock, flags);
+}
+
+static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger)
+{
+ struct plgpio *plgpio = irq_data_get_irq_chip_data(d);
+ int offset = d->irq - plgpio->irq_base;
+ void __iomem *reg_off;
+ unsigned int supported_type = 0, val;
+
+ if (offset >= plgpio->chip.ngpio)
+ return -EINVAL;
+
+ if (plgpio->regs.eit == -1)
+ supported_type = IRQ_TYPE_LEVEL_HIGH;
+ else
+ supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+
+ if (!(trigger & supported_type))
+ return -EINVAL;
+
+ if (plgpio->regs.eit == -1)
+ return 0;
+
+ reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset);
+ val = readl_relaxed(reg_off);
+
+ offset = PIN_OFFSET(offset);
+ if (trigger & IRQ_TYPE_EDGE_RISING)
+ writel_relaxed(val | (1 << offset), reg_off);
+ else
+ writel_relaxed(val & ~(1 << offset), reg_off);
+
+ return 0;
+}
+
+static struct irq_chip plgpio_irqchip = {
+ .name = "PLGPIO",
+ .irq_enable = plgpio_irq_enable,
+ .irq_disable = plgpio_irq_disable,
+ .irq_set_type = plgpio_irq_set_type,
+};
+
+static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct plgpio *plgpio = irq_get_handler_data(irq);
+ struct irq_chip *irqchip = irq_desc_get_chip(desc);
+ int regs_count, count, pin, offset, i = 0;
+ unsigned long pending;
+
+ count = plgpio->chip.ngpio;
+ regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG);
+
+ chained_irq_enter(irqchip, desc);
+ /* check all plgpio MIS registers for a possible interrupt */
+ for (; i < regs_count; i++) {
+ pending = readl_relaxed(plgpio->base + plgpio->regs.mis +
+ i * sizeof(int *));
+ if (!pending)
+ continue;
+
+ /* clear interrupts */
+ writel_relaxed(~pending, plgpio->base + plgpio->regs.mis +
+ i * sizeof(int *));
+ /*
+ * clear extra bits in last register having gpios < MAX/REG
+ * ex: Suppose there are max 102 plgpios. then last register
+ * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits
+ * so, we must not take other 28 bits into consideration for
+ * checking interrupt. so clear those bits.
+ */
+ count = count - i * MAX_GPIO_PER_REG;
+ if (count < MAX_GPIO_PER_REG)
+ pending &= (1 << count) - 1;
+
+ for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) {
+ /* get correct pin for "offset" */
+ if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) {
+ pin = plgpio->o2p(offset);
+ if (pin == -1)
+ continue;
+ } else
+ pin = offset;
+
+ /* get correct irq line number */
+ pin = i * MAX_GPIO_PER_REG + pin;
+ generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin));
+ }
+ }
+ chained_irq_exit(irqchip, desc);
+}
+
+/*
+ * pin to offset and offset to pin converter functions
+ *
+ * In spear310 there is inconsistency among bit positions in plgpio regiseters,
+ * for different plgpio pins. For example: for pin 27, bit offset is 23, pin
+ * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1
+ */
+static int spear310_p2o(int pin)
+{
+ int offset = pin;
+
+ if (pin <= 27)
+ offset += 4;
+ else if (pin <= 33)
+ offset = -1;
+ else if (pin <= 97)
+ offset -= 2;
+ else if (pin <= 101)
+ offset = 101 - pin;
+ else
+ offset = -1;
+
+ return offset;
+}
+
+int spear310_o2p(int offset)
+{
+ if (offset <= 3)
+ return 101 - offset;
+ else if (offset <= 31)
+ return offset - 4;
+ else
+ return offset + 2;
+}
+
+static int __devinit plgpio_probe_dt(struct platform_device *pdev,
+ struct plgpio *plgpio)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret = -EINVAL;
+ u32 val;
+
+ if (of_machine_is_compatible("st,spear310")) {
+ plgpio->p2o = spear310_p2o;
+ plgpio->o2p = spear310_o2p;
+ plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG |
+ PTO_RDATA_REG | PTO_MIS_REG;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) {
+ plgpio->chip.ngpio = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid ngpio field\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val))
+ plgpio->regs.enb = val;
+ else
+ plgpio->regs.enb = -1;
+
+ if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) {
+ plgpio->regs.wdata = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid wdata reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) {
+ plgpio->regs.dir = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid dir reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) {
+ plgpio->regs.ie = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid ie reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) {
+ plgpio->regs.rdata = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid rdata reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) {
+ plgpio->regs.mis = val;
+ } else {
+ dev_err(&pdev->dev, "DT: Invalid mis reg\n");
+ goto end;
+ }
+
+ if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val))
+ plgpio->regs.eit = val;
+ else
+ plgpio->regs.eit = -1;
+
+ return 0;
+
+end:
+ return ret;
+}
+static int __devinit plgpio_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct plgpio *plgpio;
+ struct resource *res;
+ int ret, irq, i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
+ return -EBUSY;
+ }
+
+ plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL);
+ if (!plgpio) {
+ dev_err(&pdev->dev, "memory allocation fail\n");
+ return -ENOMEM;
+ }
+
+ plgpio->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!plgpio->base) {
+ dev_err(&pdev->dev, "request and ioremap fail\n");
+ return -ENOMEM;
+ }
+
+ ret = plgpio_probe_dt(pdev, plgpio);
+ if (ret) {
+ dev_err(&pdev->dev, "DT probe failed\n");
+ return ret;
+ }
+
+ plgpio->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(plgpio->clk))
+ dev_warn(&pdev->dev, "clk_get() failed, work without it\n");
+
+#ifdef CONFIG_PM
+ plgpio->csave_regs = devm_kzalloc(&pdev->dev,
+ sizeof(*plgpio->csave_regs) *
+ DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG),
+ GFP_KERNEL);
+ if (!plgpio->csave_regs) {
+ dev_err(&pdev->dev, "csave registers memory allocation fail\n");
+ return -ENOMEM;
+ }
+#endif
+
+ platform_set_drvdata(pdev, plgpio);
+ spin_lock_init(&plgpio->lock);
+
+ plgpio->irq_base = -1;
+ plgpio->chip.base = -1;
+ plgpio->chip.request = plgpio_request;
+ plgpio->chip.free = plgpio_free;
+ plgpio->chip.direction_input = plgpio_direction_input;
+ plgpio->chip.direction_output = plgpio_direction_output;
+ plgpio->chip.get = plgpio_get_value;
+ plgpio->chip.set = plgpio_set_value;
+ plgpio->chip.to_irq = plgpio_to_irq;
+ plgpio->chip.label = dev_name(&pdev->dev);
+ plgpio->chip.dev = &pdev->dev;
+ plgpio->chip.owner = THIS_MODULE;
+
+ if (!IS_ERR(plgpio->clk)) {
+ ret = clk_prepare(plgpio->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "clk prepare failed\n");
+ return ret;
+ }
+ }
+
+ ret = gpiochip_add(&plgpio->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to add gpio chip\n");
+ goto unprepare_clk;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_info(&pdev->dev, "irqs not supported\n");
+ return 0;
+ }
+
+ plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0);
+ if (IS_ERR_VALUE(plgpio->irq_base)) {
+ /* we would not support irq for gpio */
+ dev_warn(&pdev->dev, "couldn't allocate irq base\n");
+ return 0;
+ }
+
+ plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio,
+ plgpio->irq_base, 0, &irq_domain_simple_ops, NULL);
+ if (WARN_ON(!plgpio->irq_domain)) {
+ dev_err(&pdev->dev, "irq domain init failed\n");
+ irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio);
+ ret = -ENXIO;
+ goto remove_gpiochip;
+ }
+
+ irq_set_chained_handler(irq, plgpio_irq_handler);
+ for (i = 0; i < plgpio->chip.ngpio; i++) {
+ irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip,
+ handle_simple_irq);
+ set_irq_flags(i + plgpio->irq_base, IRQF_VALID);
+ irq_set_chip_data(i + plgpio->irq_base, plgpio);
+ }
+
+ irq_set_handler_data(irq, plgpio);
+ dev_info(&pdev->dev, "PLGPIO registered with IRQs\n");
+
+ return 0;
+
+remove_gpiochip:
+ dev_info(&pdev->dev, "Remove gpiochip\n");
+ if (gpiochip_remove(&plgpio->chip))
+ dev_err(&pdev->dev, "unable to remove gpiochip\n");
+unprepare_clk:
+ if (!IS_ERR(plgpio->clk))
+ clk_unprepare(plgpio->clk);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int plgpio_suspend(struct device *dev)
+{
+ struct plgpio *plgpio = dev_get_drvdata(dev);
+ int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
+ void __iomem *off;
+
+ for (i = 0; i < reg_count; i++) {
+ off = plgpio->base + i * sizeof(int *);
+
+ if (plgpio->regs.enb != -1)
+ plgpio->csave_regs[i].enb =
+ readl_relaxed(plgpio->regs.enb + off);
+ if (plgpio->regs.eit != -1)
+ plgpio->csave_regs[i].eit =
+ readl_relaxed(plgpio->regs.eit + off);
+ plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata +
+ off);
+ plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir +
+ off);
+ plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off);
+ }
+
+ return 0;
+}
+
+/*
+ * This is used to correct the values in end registers. End registers contain
+ * extra bits that might be used for other purpose in platform. So, we shouldn't
+ * overwrite these bits. This macro, reads given register again, preserves other
+ * bit values (non-plgpio bits), and retain captured value (plgpio bits).
+ */
+#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \
+{ \
+ _tmp = readl_relaxed(plgpio->regs.__reg + _off); \
+ _tmp &= ~_mask; \
+ plgpio->csave_regs[i].__reg = \
+ _tmp | (plgpio->csave_regs[i].__reg & _mask); \
+}
+
+static int plgpio_resume(struct device *dev)
+{
+ struct plgpio *plgpio = dev_get_drvdata(dev);
+ int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG);
+ void __iomem *off;
+ u32 mask, tmp;
+
+ for (i = 0; i < reg_count; i++) {
+ off = plgpio->base + i * sizeof(int *);
+
+ if (i == reg_count - 1) {
+ mask = (1 << (plgpio->chip.ngpio - i *
+ MAX_GPIO_PER_REG)) - 1;
+
+ if (plgpio->regs.enb != -1)
+ plgpio_prepare_reg(enb, off, mask, tmp);
+
+ if (plgpio->regs.eit != -1)
+ plgpio_prepare_reg(eit, off, mask, tmp);
+
+ plgpio_prepare_reg(wdata, off, mask, tmp);
+ plgpio_prepare_reg(dir, off, mask, tmp);
+ plgpio_prepare_reg(ie, off, mask, tmp);
+ }
+
+ writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata +
+ off);
+ writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir +
+ off);
+
+ if (plgpio->regs.eit != -1)
+ writel_relaxed(plgpio->csave_regs[i].eit,
+ plgpio->regs.eit + off);
+
+ writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off);
+
+ if (plgpio->regs.enb != -1)
+ writel_relaxed(plgpio->csave_regs[i].enb,
+ plgpio->regs.enb + off);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume);
+
+static const struct of_device_id plgpio_of_match[] = {
+ { .compatible = "st,spear-plgpio" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, plgpio_of_match);
+
+static struct platform_driver plgpio_driver = {
+ .probe = plgpio_probe,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "spear-plgpio",
+ .pm = &plgpio_dev_pm_ops,
+ .of_match_table = of_match_ptr(plgpio_of_match),
+ },
+};
+
+static int __init plgpio_init(void)
+{
+ return platform_driver_register(&plgpio_driver);
+}
+subsys_initcall(plgpio_init);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>");
+MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
index b1fd6ee33c6c..bf78eb7f85c4 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.c
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -14,10 +14,10 @@
*/
#include <linux/err.h>
-#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_gpio.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -28,14 +28,26 @@
#define DRIVER_NAME "spear-pinmux"
-static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+static void muxregs_endisable(struct spear_pmx *pmx,
+ struct spear_muxreg *muxregs, u8 count, bool enable)
{
- return readl_relaxed(pmx->vbase + reg);
-}
+ struct spear_muxreg *muxreg;
+ u32 val, temp, j;
-static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
-{
- writel_relaxed(val, pmx->vbase + reg);
+ for (j = 0; j < count; j++) {
+ muxreg = &muxregs[j];
+
+ val = pmx_readl(pmx, muxreg->reg);
+ val &= ~muxreg->mask;
+
+ if (enable)
+ temp = muxreg->val;
+ else
+ temp = ~muxreg->val;
+
+ val |= muxreg->mask & temp;
+ pmx_writel(pmx, val, muxreg->reg);
+ }
}
static int set_mode(struct spear_pmx *pmx, int mode)
@@ -70,6 +82,17 @@ static int set_mode(struct spear_pmx *pmx, int mode)
return 0;
}
+void __devinit
+pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+ unsigned count, u16 reg)
+{
+ int i, j;
+
+ for (i = 0; i < count; i++)
+ for (j = 0; j < gpio_pingroup[i].nmuxregs; j++)
+ gpio_pingroup[i].muxregs[j].reg = reg;
+}
+
void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
{
struct spear_pingroup *pgroup;
@@ -121,9 +144,10 @@ static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
seq_printf(s, " " DRIVER_NAME);
}
-int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
- struct device_node *np_config,
- struct pinctrl_map **map, unsigned *num_maps)
+static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map,
+ unsigned *num_maps)
{
struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
struct device_node *np;
@@ -168,8 +192,9 @@ int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
}
-void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
- struct pinctrl_map *map, unsigned num_maps)
+static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map,
+ unsigned num_maps)
{
kfree(map);
}
@@ -216,9 +241,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
const struct spear_pingroup *pgroup;
const struct spear_modemux *modemux;
- struct spear_muxreg *muxreg;
- u32 val, temp;
- int i, j;
+ int i;
bool found = false;
pgroup = pmx->machdata->groups[group];
@@ -233,20 +256,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
}
found = true;
- for (j = 0; j < modemux->nmuxregs; j++) {
- muxreg = &modemux->muxregs[j];
-
- val = pmx_readl(pmx, muxreg->reg);
- val &= ~muxreg->mask;
-
- if (enable)
- temp = muxreg->val;
- else
- temp = ~muxreg->val;
-
- val |= muxreg->mask & temp;
- pmx_writel(pmx, val, muxreg->reg);
- }
+ muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs,
+ enable);
}
if (!found) {
@@ -270,12 +281,74 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
spear_pinctrl_endisable(pctldev, function, group, false);
}
+/* gpio with pinmux */
+static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx,
+ unsigned pin)
+{
+ struct spear_gpio_pingroup *gpio_pingroup;
+ int i, j;
+
+ if (!pmx->machdata->gpio_pingroups)
+ return NULL;
+
+ for (i = 0; i < pmx->machdata->ngpio_pingroups; i++) {
+ gpio_pingroup = &pmx->machdata->gpio_pingroups[i];
+
+ for (j = 0; j < gpio_pingroup->npins; j++) {
+ if (gpio_pingroup->pins[j] == pin)
+ return gpio_pingroup;
+ }
+ }
+
+ return NULL;
+}
+
+static int gpio_request_endisable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset, bool enable)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct spear_pinctrl_machdata *machdata = pmx->machdata;
+ struct spear_gpio_pingroup *gpio_pingroup;
+
+ /*
+ * Some SoC have configuration options applicable to group of pins,
+ * rather than a single pin.
+ */
+ gpio_pingroup = get_gpio_pingroup(pmx, offset);
+ if (gpio_pingroup)
+ muxregs_endisable(pmx, gpio_pingroup->muxregs,
+ gpio_pingroup->nmuxregs, enable);
+
+ /*
+ * SoC may need some extra configurations, or configurations for single
+ * pin
+ */
+ if (machdata->gpio_request_endisable)
+ machdata->gpio_request_endisable(pmx, offset, enable);
+
+ return 0;
+}
+
+static int gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ return gpio_request_endisable(pctldev, range, offset, true);
+}
+
+static void gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ gpio_request_endisable(pctldev, range, offset, false);
+}
+
static 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,
.enable = spear_pinctrl_enable,
.disable = spear_pinctrl_disable,
+ .gpio_request_enable = gpio_request_enable,
+ .gpio_disable_free = gpio_disable_free,
};
static struct pinctrl_desc spear_pinctrl_desc = {
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
index d950eb78d939..b06332719b2c 100644
--- a/drivers/pinctrl/spear/pinctrl-spear.h
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -12,11 +12,14 @@
#ifndef __PINMUX_SPEAR_H__
#define __PINMUX_SPEAR_H__
+#include <linux/gpio.h>
+#include <linux/io.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/types.h>
struct platform_device;
struct device;
+struct spear_pmx;
/**
* struct spear_pmx_mode - SPEAr pmx mode
@@ -46,6 +49,44 @@ struct spear_muxreg {
u32 val;
};
+struct spear_gpio_pingroup {
+ const unsigned *pins;
+ unsigned npins;
+ struct spear_muxreg *muxregs;
+ u8 nmuxregs;
+};
+
+/* ste: set to enable */
+#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \
+static struct spear_muxreg __pins##_muxregs[] = { \
+ { \
+ .reg = __muxreg, \
+ .mask = __mask, \
+ .val = __ste ? __mask : 0, \
+ }, \
+}
+
+#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \
+static struct spear_muxreg __pins##_muxregs[] = { \
+ { \
+ .reg = __muxreg1, \
+ .mask = __mask, \
+ .val = __ste1 ? __mask : 0, \
+ }, { \
+ .reg = __muxreg2, \
+ .mask = __mask, \
+ .val = __ste2 ? __mask : 0, \
+ }, \
+}
+
+#define GPIO_PINGROUP(__pins) \
+ { \
+ .pins = __pins, \
+ .npins = ARRAY_SIZE(__pins), \
+ .muxregs = __pins##_muxregs, \
+ .nmuxregs = ARRAY_SIZE(__pins##_muxregs), \
+ }
+
/**
* struct spear_modemux - SPEAr mode mux configuration
* @modes: mode ids supported by this group of muxregs
@@ -100,6 +141,8 @@ struct spear_function {
* @nfunctions: The numbmer of entries in @functions.
* @groups: An array describing all pin groups the pin SoC supports.
* @ngroups: The numbmer of entries in @groups.
+ * @gpio_pingroups: gpio pingroups
+ * @ngpio_pingroups: gpio pingroups count
*
* @modes_supported: Does SoC support modes
* @mode: mode configured from probe
@@ -113,6 +156,10 @@ struct spear_pinctrl_machdata {
unsigned nfunctions;
struct spear_pingroup **groups;
unsigned ngroups;
+ struct spear_gpio_pingroup *gpio_pingroups;
+ void (*gpio_request_endisable)(struct spear_pmx *pmx, int offset,
+ bool enable);
+ unsigned ngpio_pingroups;
bool modes_supported;
u16 mode;
@@ -135,7 +182,20 @@ struct spear_pmx {
};
/* exported routines */
+static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+{
+ return readl_relaxed(pmx->vbase + reg);
+}
+
+static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
+{
+ writel_relaxed(val, pmx->vbase + reg);
+}
+
void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+void __devinit
+pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup,
+ unsigned count, u16 reg);
int __devinit spear_pinctrl_probe(struct platform_device *pdev,
struct spear_pinctrl_machdata *machdata);
int __devexit spear_pinctrl_remove(struct platform_device *pdev);
diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c
index 0436fc7895d6..30134f727455 100644
--- a/drivers/pinctrl/spear/pinctrl-spear1310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear1310.c
@@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = {
&gpt64_function,
};
+static const unsigned pin18[] = { 18, };
+static const unsigned pin19[] = { 19, };
+static const unsigned pin20[] = { 20, };
+static const unsigned pin21[] = { 21, };
+static const unsigned pin22[] = { 22, };
+static const unsigned pin23[] = { 23, };
+static const unsigned pin54[] = { 54, };
+static const unsigned pin55[] = { 55, };
+static const unsigned pin56[] = { 56, };
+static const unsigned pin57[] = { 57, };
+static const unsigned pin58[] = { 58, };
+static const unsigned pin59[] = { 59, };
+static const unsigned pin60[] = { 60, };
+static const unsigned pin61[] = { 61, };
+static const unsigned pin62[] = { 62, };
+static const unsigned pin63[] = { 63, };
+static const unsigned pin143[] = { 143, };
+static const unsigned pin144[] = { 144, };
+static const unsigned pin145[] = { 145, };
+static const unsigned pin146[] = { 146, };
+static const unsigned pin147[] = { 147, };
+static const unsigned pin148[] = { 148, };
+static const unsigned pin149[] = { 149, };
+static const unsigned pin150[] = { 150, };
+static const unsigned pin151[] = { 151, };
+static const unsigned pin152[] = { 152, };
+static const unsigned pin205[] = { 205, };
+static const unsigned pin206[] = { 206, };
+static const unsigned pin211[] = { 211, };
+static const unsigned pin212[] = { 212, };
+static const unsigned pin213[] = { 213, };
+static const unsigned pin214[] = { 214, };
+static const unsigned pin215[] = { 215, };
+static const unsigned pin216[] = { 216, };
+static const unsigned pin217[] = { 217, };
+static const unsigned pin218[] = { 218, };
+static const unsigned pin219[] = { 219, };
+static const unsigned pin220[] = { 220, };
+static const unsigned pin221[] = { 221, };
+static const unsigned pin222[] = { 222, };
+static const unsigned pin223[] = { 223, };
+static const unsigned pin224[] = { 224, };
+static const unsigned pin225[] = { 225, };
+static const unsigned pin226[] = { 226, };
+static const unsigned pin227[] = { 227, };
+static const unsigned pin228[] = { 228, };
+static const unsigned pin229[] = { 229, };
+static const unsigned pin230[] = { 230, };
+static const unsigned pin231[] = { 231, };
+static const unsigned pin232[] = { 232, };
+static const unsigned pin233[] = { 233, };
+static const unsigned pin234[] = { 234, };
+static const unsigned pin235[] = { 235, };
+static const unsigned pin236[] = { 236, };
+static const unsigned pin237[] = { 237, };
+static const unsigned pin238[] = { 238, };
+static const unsigned pin239[] = { 239, };
+static const unsigned pin240[] = { 240, };
+static const unsigned pin241[] = { 241, };
+static const unsigned pin242[] = { 242, };
+static const unsigned pin243[] = { 243, };
+static const unsigned pin244[] = { 244, };
+static const unsigned pin245[] = { 245, };
+
+static const unsigned pin_grp0[] = { 173, 174, };
+static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, };
+static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189,
+ 190, 191, 192, };
+static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, };
+static const unsigned pin_grp4[] = { 199, 200, };
+static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, };
+static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, };
+static const unsigned pin_grp7[] = { 98, 99, };
+static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165,
+ 166, 167, 168, 169, 170, 171, 172, };
+
+/* Define muxreg arrays */
+DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1);
+DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1);
+DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1);
+DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1);
+DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1);
+DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1);
+DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1);
+DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1);
+DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1);
+DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1);
+DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1);
+DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1);
+DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1);
+DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1);
+DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1);
+DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1);
+DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1);
+DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1);
+DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1);
+DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1);
+DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1);
+DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1);
+DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1);
+DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1);
+DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1);
+DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1);
+DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1);
+DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1);
+DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1);
+DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1);
+DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1);
+DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1);
+DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1);
+DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1);
+DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1);
+DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1);
+DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1);
+DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1);
+DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1);
+DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1);
+DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1);
+DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1);
+DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1);
+DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1);
+DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1);
+DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1);
+DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1);
+DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1);
+DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1);
+DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1);
+
+static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = {
+ GPIO_PINGROUP(i2c0_pins),
+ GPIO_PINGROUP(ssp0_pins),
+ GPIO_PINGROUP(ssp0_cs0_pins),
+ GPIO_PINGROUP(ssp0_cs1_2_pins),
+ GPIO_PINGROUP(i2s0_pins),
+ GPIO_PINGROUP(i2s1_pins),
+ GPIO_PINGROUP(clcd_pins),
+ GPIO_PINGROUP(clcd_high_res_pins),
+ GPIO_PINGROUP(pin18),
+ GPIO_PINGROUP(pin19),
+ GPIO_PINGROUP(pin20),
+ GPIO_PINGROUP(pin21),
+ GPIO_PINGROUP(pin22),
+ GPIO_PINGROUP(pin23),
+ GPIO_PINGROUP(pin143),
+ GPIO_PINGROUP(pin144),
+ GPIO_PINGROUP(pin145),
+ GPIO_PINGROUP(pin146),
+ GPIO_PINGROUP(pin147),
+ GPIO_PINGROUP(pin148),
+ GPIO_PINGROUP(pin149),
+ GPIO_PINGROUP(pin150),
+ GPIO_PINGROUP(pin151),
+ GPIO_PINGROUP(pin152),
+ GPIO_PINGROUP(smi_2_chips_pins),
+ GPIO_PINGROUP(pin54),
+ GPIO_PINGROUP(pin55),
+ GPIO_PINGROUP(pin56),
+ GPIO_PINGROUP(pin57),
+ GPIO_PINGROUP(pin58),
+ GPIO_PINGROUP(pin59),
+ GPIO_PINGROUP(pin60),
+ GPIO_PINGROUP(pin61),
+ GPIO_PINGROUP(pin62),
+ GPIO_PINGROUP(pin63),
+ GPIO_PINGROUP(pin_grp0),
+ GPIO_PINGROUP(pin_grp1),
+ GPIO_PINGROUP(pin_grp2),
+ GPIO_PINGROUP(pin_grp3),
+ GPIO_PINGROUP(pin_grp4),
+ GPIO_PINGROUP(pin_grp5),
+ GPIO_PINGROUP(pin_grp6),
+ GPIO_PINGROUP(pin_grp7),
+ GPIO_PINGROUP(pin_grp8),
+ GPIO_PINGROUP(nand_16bit_pins),
+ GPIO_PINGROUP(pin205),
+ GPIO_PINGROUP(pin206),
+ GPIO_PINGROUP(pin211),
+ GPIO_PINGROUP(pin212),
+ GPIO_PINGROUP(pin213),
+ GPIO_PINGROUP(pin214),
+ GPIO_PINGROUP(pin215),
+ GPIO_PINGROUP(pin216),
+ GPIO_PINGROUP(pin217),
+ GPIO_PINGROUP(pin218),
+ GPIO_PINGROUP(pin219),
+ GPIO_PINGROUP(pin220),
+ GPIO_PINGROUP(pin221),
+ GPIO_PINGROUP(pin222),
+ GPIO_PINGROUP(pin223),
+ GPIO_PINGROUP(pin224),
+ GPIO_PINGROUP(pin225),
+ GPIO_PINGROUP(pin226),
+ GPIO_PINGROUP(pin227),
+ GPIO_PINGROUP(pin228),
+ GPIO_PINGROUP(pin229),
+ GPIO_PINGROUP(pin230),
+ GPIO_PINGROUP(pin231),
+ GPIO_PINGROUP(pin232),
+ GPIO_PINGROUP(pin233),
+ GPIO_PINGROUP(pin234),
+ GPIO_PINGROUP(pin235),
+ GPIO_PINGROUP(pin236),
+ GPIO_PINGROUP(pin237),
+ GPIO_PINGROUP(pin238),
+ GPIO_PINGROUP(pin239),
+ GPIO_PINGROUP(pin240),
+ GPIO_PINGROUP(pin241),
+ GPIO_PINGROUP(pin242),
+ GPIO_PINGROUP(pin243),
+ GPIO_PINGROUP(pin244),
+ GPIO_PINGROUP(pin245),
+ GPIO_PINGROUP(keyboard_rowcol6_8_pins),
+ GPIO_PINGROUP(uart0_pins),
+ GPIO_PINGROUP(uart0_modem_pins),
+ GPIO_PINGROUP(gpt0_tmr0_pins),
+ GPIO_PINGROUP(gpt0_tmr1_pins),
+ GPIO_PINGROUP(gpt1_tmr0_pins),
+ GPIO_PINGROUP(gpt1_tmr1_pins),
+ GPIO_PINGROUP(touch_xy_pins),
+};
+
static struct spear_pinctrl_machdata spear1310_machdata = {
.pins = spear1310_pins,
.npins = ARRAY_SIZE(spear1310_pins),
@@ -2425,6 +2687,8 @@ static struct spear_pinctrl_machdata spear1310_machdata = {
.ngroups = ARRAY_SIZE(spear1310_pingroups),
.functions = spear1310_functions,
.nfunctions = ARRAY_SIZE(spear1310_functions),
+ .gpio_pingroups = spear1310_gpio_pingroup,
+ .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup),
.modes_supported = false,
};
diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c
index 0606b8cf3f2c..0b4af0e5cdc1 100644
--- a/drivers/pinctrl/spear/pinctrl-spear1340.c
+++ b/drivers/pinctrl/spear/pinctrl-spear1340.c
@@ -1971,6 +1971,32 @@ static struct spear_function *spear1340_functions[] = {
&sata_function,
};
+static void gpio_request_endisable(struct spear_pmx *pmx, int pin,
+ bool enable)
+{
+ unsigned int regoffset, regindex, bitoffset;
+ unsigned int val;
+
+ /* pin++ as gpio configuration starts from 2nd bit of base register */
+ pin++;
+
+ regindex = pin / 32;
+ bitoffset = pin % 32;
+
+ if (regindex <= 3)
+ regoffset = PAD_FUNCTION_EN_1 + regindex * sizeof(int *);
+ else
+ regoffset = PAD_FUNCTION_EN_5 + (regindex - 4) * sizeof(int *);
+
+ val = pmx_readl(pmx, regoffset);
+ if (enable)
+ val &= ~(0x1 << bitoffset);
+ else
+ val |= 0x1 << bitoffset;
+
+ pmx_writel(pmx, val, regoffset);
+}
+
static struct spear_pinctrl_machdata spear1340_machdata = {
.pins = spear1340_pins,
.npins = ARRAY_SIZE(spear1340_pins),
@@ -1978,6 +2004,7 @@ static struct spear_pinctrl_machdata spear1340_machdata = {
.ngroups = ARRAY_SIZE(spear1340_pingroups),
.functions = spear1340_functions,
.nfunctions = ARRAY_SIZE(spear1340_functions),
+ .gpio_request_endisable = gpio_request_endisable,
.modes_supported = false,
};
diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c
index 4dfc2849b172..9a491007f42d 100644
--- a/drivers/pinctrl/spear/pinctrl-spear300.c
+++ b/drivers/pinctrl/spear/pinctrl-spear300.c
@@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
spear3xx_machdata.functions = spear300_functions;
spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
+ spear3xx_machdata.gpio_pingroups = NULL;
+ spear3xx_machdata.ngpio_pingroups = 0;
spear3xx_machdata.modes_supported = true;
spear3xx_machdata.pmx_modes = spear300_pmx_modes;
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
index 96883693fb7e..4d5dfe9c760a 100644
--- a/drivers/pinctrl/spear/pinctrl-spear310.c
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+ pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
+ spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
spear3xx_machdata.modes_supported = false;
diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c
index ca47b0e50780..c996e26e3b6c 100644
--- a/drivers/pinctrl/spear/pinctrl-spear320.c
+++ b/drivers/pinctrl/spear/pinctrl-spear320.c
@@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+ pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups,
+ spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG);
ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
if (ret)
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c
index 0242378f7cb8..12ee21af766b 100644
--- a/drivers/pinctrl/spear/pinctrl-spear3xx.c
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c
@@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = {
.ngroups = ARRAY_SIZE(timer_2_3_grps),
};
+/* Define muxreg arrays */
+DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0);
+DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0);
+DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0);
+DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0);
+DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0);
+DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0);
+DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0);
+DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0);
+DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0);
+DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0);
+DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0);
+DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0);
+DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0);
+DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0);
+DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0);
+
+static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = {
+ GPIO_PINGROUP(firda_pins),
+ GPIO_PINGROUP(i2c_pins),
+ GPIO_PINGROUP(ssp_cs_pins),
+ GPIO_PINGROUP(ssp_pins),
+ GPIO_PINGROUP(mii_pins),
+ GPIO_PINGROUP(gpio0_pin0_pins),
+ GPIO_PINGROUP(gpio0_pin1_pins),
+ GPIO_PINGROUP(gpio0_pin2_pins),
+ GPIO_PINGROUP(gpio0_pin3_pins),
+ GPIO_PINGROUP(gpio0_pin4_pins),
+ GPIO_PINGROUP(gpio0_pin5_pins),
+ GPIO_PINGROUP(uart0_ext_pins),
+ GPIO_PINGROUP(uart0_pins),
+ GPIO_PINGROUP(timer_0_1_pins),
+ GPIO_PINGROUP(timer_2_3_pins),
+};
+
struct spear_pinctrl_machdata spear3xx_machdata = {
.pins = spear3xx_pins,
.npins = ARRAY_SIZE(spear3xx_pins),
+ .gpio_pingroups = spear3xx_gpio_pingroup,
+ .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup),
};
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index c17ae22567e0..0c6fcb461faf 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -401,7 +401,7 @@ EXPORT_SYMBOL_GPL(rio_release_inb_pwrite);
/**
* rio_map_inb_region -- Map inbound memory region.
* @mport: Master port.
- * @lstart: physical address of memory region to be mapped
+ * @local: physical address of memory region to be mapped
* @rbase: RIO base address assigned to this window
* @size: Size of the memory region
* @rflags: Flags for mapping.
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 5c4829cba6a6..e872c8be080e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1381,22 +1381,14 @@ struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
}
EXPORT_SYMBOL_GPL(regulator_get_exclusive);
-/**
- * regulator_put - "free" the regulator source
- * @regulator: regulator source
- *
- * Note: drivers must ensure that all regulator_enable calls made on this
- * regulator source are balanced by regulator_disable calls prior to calling
- * this function.
- */
-void regulator_put(struct regulator *regulator)
+/* Locks held by regulator_put() */
+static void _regulator_put(struct regulator *regulator)
{
struct regulator_dev *rdev;
if (regulator == NULL || IS_ERR(regulator))
return;
- mutex_lock(&regulator_list_mutex);
rdev = regulator->rdev;
debugfs_remove_recursive(regulator->debugfs);
@@ -1412,6 +1404,20 @@ void regulator_put(struct regulator *regulator)
rdev->exclusive = 0;
module_put(rdev->owner);
+}
+
+/**
+ * regulator_put - "free" the regulator source
+ * @regulator: regulator source
+ *
+ * Note: drivers must ensure that all regulator_enable calls made on this
+ * regulator source are balanced by regulator_disable calls prior to calling
+ * this function.
+ */
+void regulator_put(struct regulator *regulator)
+{
+ mutex_lock(&regulator_list_mutex);
+ _regulator_put(regulator);
mutex_unlock(&regulator_list_mutex);
}
EXPORT_SYMBOL_GPL(regulator_put);
@@ -1974,7 +1980,7 @@ int regulator_is_supported_voltage(struct regulator *regulator,
if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) {
ret = regulator_get_voltage(regulator);
if (ret >= 0)
- return (min_uV >= ret && ret <= max_uV);
+ return (min_uV <= ret && ret <= max_uV);
else
return ret;
}
@@ -3365,7 +3371,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
if (ret != 0) {
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
config->ena_gpio, ret);
- goto clean;
+ goto wash;
}
rdev->ena_gpio = config->ena_gpio;
@@ -3445,10 +3451,11 @@ unset_supplies:
scrub:
if (rdev->supply)
- regulator_put(rdev->supply);
+ _regulator_put(rdev->supply);
if (rdev->ena_gpio)
gpio_free(rdev->ena_gpio);
kfree(rdev->constraints);
+wash:
device_unregister(&rdev->dev);
/* device core frees rdev */
rdev = ERR_PTR(ret);
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index e7a4780e93db..9e198e590675 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -120,15 +120,11 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev,
return vq;
}
-static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+static void __rproc_virtio_del_vqs(struct virtio_device *vdev)
{
struct virtqueue *vq, *n;
- struct rproc *rproc = vdev_to_rproc(vdev);
struct rproc_vring *rvring;
- /* power down the remote processor before deleting vqs */
- rproc_shutdown(rproc);
-
list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
rvring = vq->priv;
rvring->vq = NULL;
@@ -137,6 +133,16 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev)
}
}
+static void rproc_virtio_del_vqs(struct virtio_device *vdev)
+{
+ struct rproc *rproc = vdev_to_rproc(vdev);
+
+ /* power down the remote processor before deleting vqs */
+ rproc_shutdown(rproc);
+
+ __rproc_virtio_del_vqs(vdev);
+}
+
static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
struct virtqueue *vqs[],
vq_callback_t *callbacks[],
@@ -163,7 +169,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs,
return 0;
error:
- rproc_virtio_del_vqs(vdev);
+ __rproc_virtio_del_vqs(vdev);
return ret;
}
diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c
index 7a82337e4dee..073108dcf9e7 100644
--- a/drivers/rtc/rtc-tps65910.c
+++ b/drivers/rtc/rtc-tps65910.c
@@ -288,11 +288,11 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev)
static int __devexit tps65910_rtc_remove(struct platform_device *pdev)
{
/* leave rtc running, but disable irqs */
- struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct tps65910_rtc *tps_rtc = platform_get_drvdata(pdev);
- tps65910_rtc_alarm_irq_enable(&rtc->dev, 0);
+ tps65910_rtc_alarm_irq_enable(&pdev->dev, 0);
- rtc_device_unregister(rtc);
+ rtc_device_unregister(tps_rtc->rtc);
return 0;
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 9ffb6d5f17aa..4ed343e4eb41 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -44,7 +44,6 @@
#define RAW3215_NR_CCWS 3
#define RAW3215_TIMEOUT HZ/10 /* time for delayed output */
-#define RAW3215_FIXED 1 /* 3215 console device is not be freed */
#define RAW3215_WORKING 4 /* set if a request is being worked on */
#define RAW3215_THROTTLED 8 /* set if reading is disabled */
#define RAW3215_STOPPED 16 /* set if writing is disabled */
@@ -339,8 +338,10 @@ static void raw3215_wakeup(unsigned long data)
struct tty_struct *tty;
tty = tty_port_tty_get(&raw->port);
- tty_wakeup(tty);
- tty_kref_put(tty);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
}
/*
@@ -629,8 +630,7 @@ static void raw3215_shutdown(struct raw3215_info *raw)
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
- if (!(raw->port.flags & ASYNC_INITIALIZED) ||
- (raw->flags & RAW3215_FIXED))
+ if (!(raw->port.flags & ASYNC_INITIALIZED))
return;
/* Wait for outstanding requests, then free irq */
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
@@ -926,8 +926,6 @@ static int __init con3215_init(void)
dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq;
- raw->flags |= RAW3215_FIXED;
-
/* Request the console irq */
if (raw3215_startup(raw) != 0) {
raw3215_free_info(raw);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3e25d3150456..4d6ba00d0047 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -2942,13 +2942,33 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
QETH_DBF_TEXT(SETUP, 2, "qipasscb");
cmd = (struct qeth_ipa_cmd *) data;
+
+ switch (cmd->hdr.return_code) {
+ case IPA_RC_NOTSUPP:
+ case IPA_RC_L2_UNSUPPORTED_CMD:
+ QETH_DBF_TEXT(SETUP, 2, "ipaunsup");
+ card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS;
+ card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS;
+ return -0;
+ default:
+ if (cmd->hdr.return_code) {
+ QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Unhandled "
+ "rc=%d\n",
+ dev_name(&card->gdev->dev),
+ cmd->hdr.return_code);
+ return 0;
+ }
+ }
+
if (cmd->hdr.prot_version == QETH_PROT_IPV4) {
card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported;
card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
- } else {
+ } else if (cmd->hdr.prot_version == QETH_PROT_IPV6) {
card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
- }
+ } else
+ QETH_DBF_MESSAGE(1, "%s IPA_CMD_QIPASSIST: Flawed LIC detected"
+ "\n", dev_name(&card->gdev->dev));
QETH_DBF_TEXT(SETUP, 2, "suppenbl");
QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_supported);
QETH_DBF_TEXT_(SETUP, 2, "%08x", (__u32)cmd->hdr.ipa_enabled);
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index e67e0258aec5..fddb62654b6a 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -626,10 +626,13 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
QETH_DBF_TEXT(SETUP, 2, "doL2init");
QETH_DBF_TEXT_(SETUP, 2, "doL2%s", CARD_BUS_ID(card));
- rc = qeth_query_setadapterparms(card);
- if (rc) {
- QETH_DBF_MESSAGE(2, "could not query adapter parameters on "
- "device %s: x%x\n", CARD_BUS_ID(card), rc);
+ if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
+ rc = qeth_query_setadapterparms(card);
+ if (rc) {
+ QETH_DBF_MESSAGE(2, "could not query adapter "
+ "parameters on device %s: x%x\n",
+ CARD_BUS_ID(card), rc);
+ }
}
if (card->info.type == QETH_CARD_TYPE_IQD ||
@@ -676,7 +679,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
return -ERESTARTSYS;
}
rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
- if (!rc)
+ if (!rc || (rc == IPA_RC_L2_MAC_NOT_FOUND))
rc = qeth_l2_send_setmac(card, addr->sa_data);
return rc ? -EINVAL : 0;
}
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index c1bafc3f3fb1..9594ab62702b 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -1972,7 +1972,7 @@ sci_io_request_frame_handler(struct isci_request *ireq,
frame_index,
(void **)&frame_buffer);
- sci_controller_copy_sata_response(&ireq->stp.req,
+ sci_controller_copy_sata_response(&ireq->stp.rsp,
frame_header,
frame_buffer);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 16b7a72a70c4..3b2365c8eab2 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1276,7 +1276,7 @@ struct megasas_evt_detail {
} __attribute__ ((packed));
struct megasas_aen_event {
- struct work_struct hotplug_work;
+ struct delayed_work hotplug_work;
struct megasas_instance *instance;
};
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index d2c5366aff7f..e4f2baacf1e1 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -2060,9 +2060,9 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
} else {
ev->instance = instance;
instance->ev = ev;
- INIT_WORK(&ev->hotplug_work, megasas_aen_polling);
- schedule_delayed_work(
- (struct delayed_work *)&ev->hotplug_work, 0);
+ INIT_DELAYED_WORK(&ev->hotplug_work,
+ megasas_aen_polling);
+ schedule_delayed_work(&ev->hotplug_work, 0);
}
}
}
@@ -4352,8 +4352,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
/* cancel the delayed work if this work still in queue */
if (instance->ev != NULL) {
struct megasas_aen_event *ev = instance->ev;
- cancel_delayed_work_sync(
- (struct delayed_work *)&ev->hotplug_work);
+ cancel_delayed_work_sync(&ev->hotplug_work);
instance->ev = NULL;
}
@@ -4545,8 +4544,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
/* cancel the delayed work if this work still in queue*/
if (instance->ev != NULL) {
struct megasas_aen_event *ev = instance->ev;
- cancel_delayed_work_sync(
- (struct delayed_work *)&ev->hotplug_work);
+ cancel_delayed_work_sync(&ev->hotplug_work);
instance->ev = NULL;
}
@@ -5190,7 +5188,7 @@ static void
megasas_aen_polling(struct work_struct *work)
{
struct megasas_aen_event *ev =
- container_of(work, struct megasas_aen_event, hotplug_work);
+ container_of(work, struct megasas_aen_event, hotplug_work.work);
struct megasas_instance *instance = ev->instance;
union megasas_evt_class_locale class_locale;
struct Scsi_Host *host;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2936b447cae9..2c0d0ec8150b 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -55,6 +55,7 @@
#include <linux/cpu.h>
#include <linux/mutex.h>
#include <linux/async.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -1062,6 +1063,50 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
EXPORT_SYMBOL_GPL(scsi_get_vpd_page);
/**
+ * scsi_report_opcode - Find out if a given command opcode is supported
+ * @sdev: scsi device to query
+ * @buffer: scratch buffer (must be at least 20 bytes long)
+ * @len: length of buffer
+ * @opcode: opcode for command to look up
+ *
+ * Uses the REPORT SUPPORTED OPERATION CODES to look up the given
+ * opcode. Returns 0 if RSOC fails or if the command opcode is
+ * unsupported. Returns 1 if the device claims to support the command.
+ */
+int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
+ unsigned int len, unsigned char opcode)
+{
+ unsigned char cmd[16];
+ struct scsi_sense_hdr sshdr;
+ int result;
+
+ if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3)
+ return 0;
+
+ memset(cmd, 0, 16);
+ cmd[0] = MAINTENANCE_IN;
+ cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES;
+ cmd[2] = 1; /* One command format */
+ cmd[3] = opcode;
+ put_unaligned_be32(len, &cmd[6]);
+ memset(buffer, 0, len);
+
+ result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len,
+ &sshdr, 30 * HZ, 3, NULL);
+
+ if (result && scsi_sense_valid(&sshdr) &&
+ sshdr.sense_key == ILLEGAL_REQUEST &&
+ (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00)
+ return 0;
+
+ if ((buffer[1] & 3) == 3) /* Command supported */
+ return 1;
+
+ return 0;
+}
+EXPORT_SYMBOL(scsi_report_opcode);
+
+/**
* scsi_device_get - get an additional reference to a scsi_device
* @sdev: device to get a reference to
*
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index da36a3a81a9e..9032e910bca3 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -900,11 +900,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
action = ACTION_FAIL;
error = -EILSEQ;
/* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
- } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
- (cmd->cmnd[0] == UNMAP ||
- cmd->cmnd[0] == WRITE_SAME_16 ||
- cmd->cmnd[0] == WRITE_SAME)) {
- description = "Discard failure";
+ } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) {
+ switch (cmd->cmnd[0]) {
+ case UNMAP:
+ description = "Discard failure";
+ break;
+ case WRITE_SAME:
+ case WRITE_SAME_16:
+ if (cmd->cmnd[1] & 0x8)
+ description = "Discard failure";
+ else
+ description =
+ "Write same failure";
+ break;
+ default:
+ description = "Invalid command failure";
+ break;
+ }
action = ACTION_FAIL;
error = -EREMOTEIO;
} else
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 12f6fdfc1147..352bc77b7c88 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -99,6 +99,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
#endif
static void sd_config_discard(struct scsi_disk *, unsigned int);
+static void sd_config_write_same(struct scsi_disk *);
static int sd_revalidate_disk(struct gendisk *);
static void sd_unlock_native_capacity(struct gendisk *disk);
static int sd_probe(struct device *);
@@ -395,6 +396,45 @@ sd_store_max_medium_access_timeouts(struct device *dev,
return err ? err : count;
}
+static ssize_t
+sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+
+ return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks);
+}
+
+static ssize_t
+sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(dev);
+ struct scsi_device *sdp = sdkp->device;
+ unsigned long max;
+ int err;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (sdp->type != TYPE_DISK)
+ return -EINVAL;
+
+ err = kstrtoul(buf, 10, &max);
+
+ if (err)
+ return err;
+
+ if (max == 0)
+ sdp->no_write_same = 1;
+ else if (max <= SD_MAX_WS16_BLOCKS)
+ sdkp->max_ws_blocks = max;
+
+ sd_config_write_same(sdkp);
+
+ return count;
+}
+
static struct device_attribute sd_disk_attrs[] = {
__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
sd_store_cache_type),
@@ -410,6 +450,8 @@ static struct device_attribute sd_disk_attrs[] = {
__ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL),
__ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode,
sd_store_provisioning_mode),
+ __ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR,
+ sd_show_write_same_blocks, sd_store_write_same_blocks),
__ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR,
sd_show_max_medium_access_timeouts,
sd_store_max_medium_access_timeouts),
@@ -561,19 +603,23 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
return;
case SD_LBP_UNMAP:
- max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff);
+ max_blocks = min_not_zero(sdkp->max_unmap_blocks,
+ (u32)SD_MAX_WS16_BLOCKS);
break;
case SD_LBP_WS16:
- max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff);
+ max_blocks = min_not_zero(sdkp->max_ws_blocks,
+ (u32)SD_MAX_WS16_BLOCKS);
break;
case SD_LBP_WS10:
- max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff);
+ max_blocks = min_not_zero(sdkp->max_ws_blocks,
+ (u32)SD_MAX_WS10_BLOCKS);
break;
case SD_LBP_ZERO:
- max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff);
+ max_blocks = min_not_zero(sdkp->max_ws_blocks,
+ (u32)SD_MAX_WS10_BLOCKS);
q->limits.discard_zeroes_data = 1;
break;
}
@@ -583,29 +629,26 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
}
/**
- * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device
+ * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device
* @sdp: scsi device to operate one
* @rq: Request to prepare
*
* Will issue either UNMAP or WRITE SAME(16) depending on preference
* indicated by target device.
**/
-static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
+static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
{
struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
- struct bio *bio = rq->bio;
- sector_t sector = bio->bi_sector;
- unsigned int nr_sectors = bio_sectors(bio);
+ sector_t sector = blk_rq_pos(rq);
+ unsigned int nr_sectors = blk_rq_sectors(rq);
+ unsigned int nr_bytes = blk_rq_bytes(rq);
unsigned int len;
int ret;
char *buf;
struct page *page;
- if (sdkp->device->sector_size == 4096) {
- sector >>= 3;
- nr_sectors >>= 3;
- }
-
+ sector >>= ilog2(sdp->sector_size) - 9;
+ nr_sectors >>= ilog2(sdp->sector_size) - 9;
rq->timeout = SD_TIMEOUT;
memset(rq->cmd, 0, rq->cmd_len);
@@ -660,6 +703,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq)
blk_add_request_payload(rq, page, len);
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
rq->buffer = page_address(page);
+ rq->__data_len = nr_bytes;
out:
if (ret != BLKPREP_OK) {
@@ -669,6 +713,83 @@ out:
return ret;
}
+static void sd_config_write_same(struct scsi_disk *sdkp)
+{
+ struct request_queue *q = sdkp->disk->queue;
+ unsigned int logical_block_size = sdkp->device->sector_size;
+ unsigned int blocks = 0;
+
+ if (sdkp->device->no_write_same) {
+ sdkp->max_ws_blocks = 0;
+ goto out;
+ }
+
+ /* Some devices can not handle block counts above 0xffff despite
+ * supporting WRITE SAME(16). Consequently we default to 64k
+ * blocks per I/O unless the device explicitly advertises a
+ * bigger limit.
+ */
+ if (sdkp->max_ws_blocks == 0)
+ sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS;
+
+ if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS)
+ blocks = min_not_zero(sdkp->max_ws_blocks,
+ (u32)SD_MAX_WS16_BLOCKS);
+ else
+ blocks = min_not_zero(sdkp->max_ws_blocks,
+ (u32)SD_MAX_WS10_BLOCKS);
+
+out:
+ blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9));
+}
+
+/**
+ * sd_setup_write_same_cmnd - write the same data to multiple blocks
+ * @sdp: scsi device to operate one
+ * @rq: Request to prepare
+ *
+ * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on
+ * preference indicated by target device.
+ **/
+static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq)
+{
+ struct scsi_disk *sdkp = scsi_disk(rq->rq_disk);
+ struct bio *bio = rq->bio;
+ sector_t sector = blk_rq_pos(rq);
+ unsigned int nr_sectors = blk_rq_sectors(rq);
+ unsigned int nr_bytes = blk_rq_bytes(rq);
+ int ret;
+
+ if (sdkp->device->no_write_same)
+ return BLKPREP_KILL;
+
+ BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size);
+
+ sector >>= ilog2(sdp->sector_size) - 9;
+ nr_sectors >>= ilog2(sdp->sector_size) - 9;
+
+ rq->__data_len = sdp->sector_size;
+ rq->timeout = SD_WRITE_SAME_TIMEOUT;
+ memset(rq->cmd, 0, rq->cmd_len);
+
+ if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) {
+ rq->cmd_len = 16;
+ rq->cmd[0] = WRITE_SAME_16;
+ put_unaligned_be64(sector, &rq->cmd[2]);
+ put_unaligned_be32(nr_sectors, &rq->cmd[10]);
+ } else {
+ rq->cmd_len = 10;
+ rq->cmd[0] = WRITE_SAME;
+ put_unaligned_be32(sector, &rq->cmd[2]);
+ put_unaligned_be16(nr_sectors, &rq->cmd[7]);
+ }
+
+ ret = scsi_setup_blk_pc_cmnd(sdp, rq);
+ rq->__data_len = nr_bytes;
+
+ return ret;
+}
+
static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq)
{
rq->timeout = SD_FLUSH_TIMEOUT;
@@ -712,7 +833,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
* block PC requests to make life easier.
*/
if (rq->cmd_flags & REQ_DISCARD) {
- ret = scsi_setup_discard_cmnd(sdp, rq);
+ ret = sd_setup_discard_cmnd(sdp, rq);
+ goto out;
+ } else if (rq->cmd_flags & REQ_WRITE_SAME) {
+ ret = sd_setup_write_same_cmnd(sdp, rq);
goto out;
} else if (rq->cmd_flags & REQ_FLUSH) {
ret = scsi_setup_flush_cmnd(sdp, rq);
@@ -1482,12 +1606,21 @@ static int sd_done(struct scsi_cmnd *SCpnt)
unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);
struct scsi_sense_hdr sshdr;
struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
+ struct request *req = SCpnt->request;
int sense_valid = 0;
int sense_deferred = 0;
unsigned char op = SCpnt->cmnd[0];
+ unsigned char unmap = SCpnt->cmnd[1] & 8;
- if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result)
- scsi_set_resid(SCpnt, 0);
+ if (req->cmd_flags & REQ_DISCARD || req->cmd_flags & REQ_WRITE_SAME) {
+ if (!result) {
+ good_bytes = blk_rq_bytes(req);
+ scsi_set_resid(SCpnt, 0);
+ } else {
+ good_bytes = 0;
+ scsi_set_resid(SCpnt, blk_rq_bytes(req));
+ }
+ }
if (result) {
sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
@@ -1536,9 +1669,25 @@ static int sd_done(struct scsi_cmnd *SCpnt)
if (sshdr.asc == 0x10) /* DIX: Host detected corruption */
good_bytes = sd_completed_bytes(SCpnt);
/* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */
- if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) &&
- (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME))
- sd_config_discard(sdkp, SD_LBP_DISABLE);
+ if (sshdr.asc == 0x20 || sshdr.asc == 0x24) {
+ switch (op) {
+ case UNMAP:
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
+ break;
+ case WRITE_SAME_16:
+ case WRITE_SAME:
+ if (unmap)
+ sd_config_discard(sdkp, SD_LBP_DISABLE);
+ else {
+ sdkp->device->no_write_same = 1;
+ sd_config_write_same(sdkp);
+
+ good_bytes = 0;
+ req->__data_len = blk_rq_bytes(req);
+ req->cmd_flags |= REQ_QUIET;
+ }
+ }
+ }
break;
default:
break;
@@ -2374,9 +2523,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
if (buffer[3] == 0x3c) {
unsigned int lba_count, desc_count;
- sdkp->max_ws_blocks =
- (u32) min_not_zero(get_unaligned_be64(&buffer[36]),
- (u64)0xffffffff);
+ sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]);
if (!sdkp->lbpme)
goto out;
@@ -2469,6 +2616,13 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp)
kfree(buffer);
}
+static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
+{
+ if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE,
+ WRITE_SAME_16))
+ sdkp->ws16 = 1;
+}
+
static int sd_try_extended_inquiry(struct scsi_device *sdp)
{
/*
@@ -2528,6 +2682,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_write_protect_flag(sdkp, buffer);
sd_read_cache_type(sdkp, buffer);
sd_read_app_tag_own(sdkp, buffer);
+ sd_read_write_same(sdkp, buffer);
}
sdkp->first_scan = 0;
@@ -2545,6 +2700,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
blk_queue_flush(sdkp->disk->queue, flush);
set_capacity(disk, sdkp->capacity);
+ sd_config_write_same(sdkp);
kfree(buffer);
out:
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 47c52a6d733c..74a1e4ca5401 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -14,6 +14,7 @@
#define SD_TIMEOUT (30 * HZ)
#define SD_MOD_TIMEOUT (75 * HZ)
#define SD_FLUSH_TIMEOUT (60 * HZ)
+#define SD_WRITE_SAME_TIMEOUT (120 * HZ)
/*
* Number of allowed retries
@@ -39,6 +40,11 @@ enum {
};
enum {
+ SD_MAX_WS10_BLOCKS = 0xffff,
+ SD_MAX_WS16_BLOCKS = 0x7fffff,
+};
+
+enum {
SD_LBP_FULL = 0, /* Full logical block provisioning */
SD_LBP_UNMAP, /* Use UNMAP command */
SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */
@@ -77,6 +83,7 @@ struct scsi_disk {
unsigned lbpws : 1;
unsigned lbpws10 : 1;
unsigned lbpvpd : 1;
+ unsigned ws16 : 1;
};
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
index f2ffd963f1c3..d0cafd637199 100644
--- a/drivers/staging/android/android_alarm.h
+++ b/drivers/staging/android/android_alarm.h
@@ -51,12 +51,10 @@ enum android_alarm_return_flags {
#define ANDROID_ALARM_WAIT _IO('a', 1)
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
-#define ALARM_IOR(c, type, size) _IOR('a', (c) | ((type) << 4), size)
-
/* Set alarm */
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
-#define ANDROID_ALARM_GET_TIME(type) ALARM_IOR(4, type, struct timespec)
+#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 9097155e9ebe..dcecbfb17243 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1819,8 +1819,10 @@ void target_execute_cmd(struct se_cmd *cmd)
/*
* If the received CDB has aleady been aborted stop processing it here.
*/
- if (transport_check_aborted_status(cmd, 1))
+ if (transport_check_aborted_status(cmd, 1)) {
+ complete(&cmd->t_transport_stop_comp);
return;
+ }
/*
* Determine if IOCTL context caller in requesting the stopping of this
@@ -3067,7 +3069,7 @@ void transport_send_task_abort(struct se_cmd *cmd)
unsigned long flags;
spin_lock_irqsave(&cmd->t_state_lock, flags);
- if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) {
+ if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) {
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
return;
}
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index a5dec1ca1b82..13ee53bd0bf6 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -424,7 +424,6 @@ static void hvc_hangup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
- int temp_open_count;
if (!hp)
return;
@@ -444,7 +443,6 @@ static void hvc_hangup(struct tty_struct *tty)
return;
}
- temp_open_count = hp->port.count;
hp->port.count = 0;
spin_unlock_irqrestore(&hp->port.lock, flags);
tty_port_tty_set(&hp->port, NULL);
@@ -453,11 +451,6 @@ static void hvc_hangup(struct tty_struct *tty)
if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data);
-
- while(temp_open_count) {
- --temp_open_count;
- tty_port_put(&hp->port);
- }
}
/*
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 3d7e1ee2fa57..65f891be12d1 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -39,6 +39,7 @@
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
#include <linux/uaccess.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
struct atmel_uart_data *pdata = pdev->dev.platform_data;
void *data;
int ret = -ENODEV;
+ struct pinctrl *pinctrl;
BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1));
@@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev)
atmel_init_port(port, pdev);
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto err;
+ }
+
if (!atmel_use_dma_rx(&port->uart)) {
ret = -ENOMEM;
data = kmalloc(sizeof(struct atmel_uart_char)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 2bc28a59d385..1ab1d2c66de4 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1239,6 +1239,7 @@ static int __devexit max310x_remove(struct spi_device *spi)
static const struct spi_device_id max310x_id_table[] = {
{ "max3107", MAX310X_TYPE_MAX3107 },
{ "max3108", MAX310X_TYPE_MAX3108 },
+ { }
};
MODULE_DEVICE_TABLE(spi, max310x_id_table);
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f87d7e8964bf..4e0d0c3734b3 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -539,25 +539,25 @@ static void insert_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x);
+ scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2);
scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
- (vc->vc_cols - vc->vc_x) / 2 + 1);
+ vc->vc_cols - vc->vc_x);
}
static void delete_char(struct vc_data *vc, unsigned int nr)
{
unsigned short *p = (unsigned short *) vc->vc_pos;
- scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr);
+ scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2);
scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char,
nr * 2);
vc->vc_need_wrap = 0;
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p,
- (vc->vc_cols - vc->vc_x) / 2);
+ vc->vc_cols - vc->vc_x);
}
static int softcursor_original;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 1e741bca0265..f034716190ff 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2151,8 +2151,15 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
struct usb_hcd *hcd = __hcd;
+ unsigned long flags;
irqreturn_t rc;
+ /* IRQF_DISABLED doesn't work correctly with shared IRQs
+ * when the first handler doesn't use it. So let's just
+ * assume it's never used.
+ */
+ local_irq_save(flags);
+
if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
rc = IRQ_NONE;
else if (hcd->driver->irq(hcd) == IRQ_NONE)
@@ -2160,6 +2167,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
else
rc = IRQ_HANDLED;
+ local_irq_restore(flags);
return rc;
}
EXPORT_SYMBOL_GPL(usb_hcd_irq);
@@ -2347,6 +2355,14 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
int retval;
if (hcd->driver->irq) {
+
+ /* IRQF_DISABLED doesn't work as advertised when used together
+ * with IRQF_SHARED. As usb_hcd_irq() will always disable
+ * interrupts we can remove it here.
+ */
+ if (irqflags & IRQF_SHARED)
+ irqflags &= ~IRQF_DISABLED;
+
snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",
hcd->driver->description, hcd->self.busnum);
retval = request_irq(irqnum, &usb_hcd_irq, irqflags,
diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c
index e426ad626d74..4bfa78af379c 100644
--- a/drivers/usb/early/ehci-dbgp.c
+++ b/drivers/usb/early/ehci-dbgp.c
@@ -20,6 +20,7 @@
#include <linux/usb/ehci_def.h>
#include <linux/delay.h>
#include <linux/serial_core.h>
+#include <linux/kconfig.h>
#include <linux/kgdb.h>
#include <linux/kthread.h>
#include <asm/io.h>
@@ -614,12 +615,6 @@ err:
return -ENODEV;
}
-int dbgp_external_startup(struct usb_hcd *hcd)
-{
- return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup();
-}
-EXPORT_SYMBOL_GPL(dbgp_external_startup);
-
static int ehci_reset_port(int port)
{
u32 portsc;
@@ -979,6 +974,7 @@ struct console early_dbgp_console = {
.index = -1,
};
+#if IS_ENABLED(CONFIG_USB_EHCI_HCD)
int dbgp_reset_prep(struct usb_hcd *hcd)
{
int ret = xen_dbgp_reset_prep(hcd);
@@ -1007,6 +1003,13 @@ int dbgp_reset_prep(struct usb_hcd *hcd)
}
EXPORT_SYMBOL_GPL(dbgp_reset_prep);
+int dbgp_external_startup(struct usb_hcd *hcd)
+{
+ return xen_dbgp_external_startup(hcd) ?: _dbgp_external_startup();
+}
+EXPORT_SYMBOL_GPL(dbgp_external_startup);
+#endif /* USB_EHCI_HCD */
+
#ifdef CONFIG_KGDB
static char kgdbdbgp_buf[DBGP_MAX_PACKET];
diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c
index ca759652626b..aa0f328922df 100644
--- a/drivers/usb/host/ehci-ls1x.c
+++ b/drivers/usb/host/ehci-ls1x.c
@@ -113,7 +113,7 @@ static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
goto err_put_hcd;
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret)
goto err_put_hcd;
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
index 84201cd1a472..41e378f17c66 100644
--- a/drivers/usb/host/ohci-xls.c
+++ b/drivers/usb/host/ohci-xls.c
@@ -56,7 +56,7 @@ static int ohci_xls_probe_internal(const struct hc_driver *driver,
goto err3;
}
- retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
goto err4;
return retval;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index d0b87e7b4abf..b6b84dacc791 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -707,11 +707,12 @@ static void rxstate(struct musb *musb, struct musb_request *req)
fifo_count = musb_readw(epio, MUSB_RXCOUNT);
/*
- * use mode 1 only if we expect data of at least ep packet_sz
- * and have not yet received a short packet
+ * Enable Mode 1 on RX transfers only when short_not_ok flag
+ * is set. Currently short_not_ok flag is set only from
+ * file_storage and f_mass_storage drivers
*/
- if ((request->length - request->actual >= musb_ep->packet_sz) &&
- (fifo_count >= musb_ep->packet_sz))
+
+ if (request->short_not_ok && fifo_count == musb_ep->packet_sz)
use_mode_1 = 1;
else
use_mode_1 = 0;
@@ -727,6 +728,27 @@ static void rxstate(struct musb *musb, struct musb_request *req)
c = musb->dma_controller;
channel = musb_ep->dma;
+ /* We use DMA Req mode 0 in rx_csr, and DMA controller operates in
+ * mode 0 only. So we do not get endpoint interrupts due to DMA
+ * completion. We only get interrupts from DMA controller.
+ *
+ * We could operate in DMA mode 1 if we knew the size of the tranfer
+ * in advance. For mass storage class, request->length = what the host
+ * sends, so that'd work. But for pretty much everything else,
+ * request->length is routinely more than what the host sends. For
+ * most these gadgets, end of is signified either by a short packet,
+ * or filling the last byte of the buffer. (Sending extra data in
+ * that last pckate should trigger an overflow fault.) But in mode 1,
+ * we don't get DMA completion interrupt for short packets.
+ *
+ * Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),
+ * to get endpoint interrupt on every DMA req, but that didn't seem
+ * to work reliably.
+ *
+ * REVISIT an updated g_file_storage can set req->short_not_ok, which
+ * then becomes usable as a runtime "use mode 1" hint...
+ */
+
/* Experimental: Mode1 works with mass storage use cases */
if (use_mode_1) {
csr |= MUSB_RXCSR_AUTOCLEAR;
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index d62a91fedc22..0e62f504410e 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -65,7 +65,7 @@ static int __devinit ux500_probe(struct platform_device *pdev)
struct platform_device *musb;
struct ux500_glue *glue;
struct clk *clk;
-
+ int musbid;
int ret = -ENOMEM;
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index d8c8a42bff3e..6223062d5d1b 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -58,7 +58,7 @@ config USB_ULPI_VIEWPORT
config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
- depends on TWL4030_CORE && REGULATOR_TWL4030
+ depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS
select USB_OTG_UTILS
help
Enable this to support the USB OTG transceiver on TWL4030
@@ -68,7 +68,7 @@ config TWL4030_USB
config TWL6030_USB
tristate "TWL6030 USB Transceiver Driver"
- depends on TWL4030_CORE && OMAP_USB2
+ depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS
select USB_OTG_UTILS
help
Enable this to support the USB OTG transceiver on TWL6030
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 7179b0c5f814..cff8dd5b462d 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -2430,7 +2430,7 @@ static void keyspan_release(struct usb_serial *serial)
static int keyspan_port_probe(struct usb_serial_port *port)
{
struct usb_serial *serial = port->serial;
- struct keyspan_port_private *s_priv;
+ struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
struct callbacks *cback;
@@ -2445,7 +2445,6 @@ static int keyspan_port_probe(struct usb_serial_port *port)
if (!p_priv)
return -ENOMEM;
- s_priv = usb_get_serial_data(port->serial);
p_priv->device_details = d_details;
/* Setup values for the various callback routines */
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5dee7d61241e..edc64bb6f457 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -158,6 +158,7 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_HIGHSPEED 0x8001
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED 0x9000
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
+#define NOVATELWIRELESS_PRODUCT_E362 0x9010
#define NOVATELWIRELESS_PRODUCT_G1 0xA001
#define NOVATELWIRELESS_PRODUCT_G1_M 0xA002
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
@@ -193,6 +194,9 @@ static void option_instat_callback(struct urb *urb);
#define DELL_PRODUCT_5730_MINICARD_TELUS 0x8181
#define DELL_PRODUCT_5730_MINICARD_VZW 0x8182
+#define DELL_PRODUCT_5800_MINICARD_VZW 0x8195 /* Novatel E362 */
+#define DELL_PRODUCT_5800_V2_MINICARD_VZW 0x8196 /* Novatel E362 */
+
#define KYOCERA_VENDOR_ID 0x0c88
#define KYOCERA_PRODUCT_KPC650 0x17da
#define KYOCERA_PRODUCT_KPC680 0x180a
@@ -283,6 +287,7 @@ static void option_instat_callback(struct urb *urb);
/* ALCATEL PRODUCTS */
#define ALCATEL_VENDOR_ID 0x1bbb
#define ALCATEL_PRODUCT_X060S_X200 0x0000
+#define ALCATEL_PRODUCT_X220_X500D 0x0017
#define PIRELLI_VENDOR_ID 0x1266
#define PIRELLI_PRODUCT_C100_1 0x1002
@@ -706,6 +711,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_G2) },
/* Novatel Ovation MC551 a.k.a. Verizon USB551L */
{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@@ -728,6 +734,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_SPRINT) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_TELUS) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5730_MINICARD_VZW) }, /* Dell Wireless 5730 Mobile Broadband EVDO/HSPA Mini-Card */
+ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
@@ -1157,6 +1165,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S_X200),
.driver_info = (kernel_ulong_t)&alcatel_x200_blacklist
},
+ { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X220_X500D) },
{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 61a73ad1a187..a3e9c095f0d8 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -455,9 +455,6 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,
struct usb_serial *serial = port->serial;
struct urb *urb;
- if (endpoint == -1)
- return NULL; /* endpoint not needed */
-
urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
if (urb == NULL) {
dev_dbg(&serial->interface->dev,
@@ -489,6 +486,9 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
init_usb_anchor(&portdata->delayed);
for (i = 0; i < N_IN_URB; i++) {
+ if (!port->bulk_in_size)
+ break;
+
buffer = (u8 *)__get_free_page(GFP_KERNEL);
if (!buffer)
goto bail_out_error;
@@ -502,8 +502,8 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
}
for (i = 0; i < N_OUT_URB; i++) {
- if (port->bulk_out_endpointAddress == -1)
- continue;
+ if (!port->bulk_out_size)
+ break;
buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);
if (!buffer)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index a3d54366afcc..92f35abee92d 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -186,6 +186,12 @@ static int slave_configure(struct scsi_device *sdev)
/* Some devices don't handle VPD pages correctly */
sdev->skip_vpd_pages = 1;
+ /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */
+ sdev->no_report_opcodes = 1;
+
+ /* Do not attempt to use WRITE SAME */
+ sdev->no_write_same = 1;
+
/* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number.
* If this device makes that mistake, tell the sd driver. */
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 99ac2cb08b43..dedaf81d8f36 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1076,7 +1076,7 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len,
}
_iov = iov + ret;
size = reg->memory_size - addr + reg->guest_phys_addr;
- _iov->iov_len = min((u64)len, size);
+ _iov->iov_len = min((u64)len - s, size);
_iov->iov_base = (void __user *)(unsigned long)
(reg->userspace_addr + addr - reg->guest_phys_addr);
s += size;
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index d64ac3842884..bee92846cfab 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -365,11 +365,20 @@ struct platform_device *dsi_get_dsidev_from_id(int module)
struct omap_dss_output *out;
enum omap_dss_output_id id;
- id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
+ switch (module) {
+ case 0:
+ id = OMAP_DSS_OUTPUT_DSI1;
+ break;
+ case 1:
+ id = OMAP_DSS_OUTPUT_DSI2;
+ break;
+ default:
+ return NULL;
+ }
out = omap_dss_get_output(id);
- return out->pdev;
+ return out ? out->pdev : NULL;
}
static inline void dsi_write_reg(struct platform_device *dsidev,
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
index 2ab1c3e96553..5f6eea801b06 100644
--- a/drivers/video/omap2/dss/dss.c
+++ b/drivers/video/omap2/dss/dss.c
@@ -697,11 +697,15 @@ static int dss_get_clocks(void)
dss.dss_clk = clk;
- clk = clk_get(NULL, dss.feat->clk_name);
- if (IS_ERR(clk)) {
- DSSERR("Failed to get %s\n", dss.feat->clk_name);
- r = PTR_ERR(clk);
- goto err;
+ if (dss.feat->clk_name) {
+ clk = clk_get(NULL, dss.feat->clk_name);
+ if (IS_ERR(clk)) {
+ DSSERR("Failed to get %s\n", dss.feat->clk_name);
+ r = PTR_ERR(clk);
+ goto err;
+ }
+ } else {
+ clk = NULL;
}
dss.dpll4_m4_ck = clk;
@@ -805,10 +809,10 @@ static int __init dss_init_features(struct device *dev)
if (cpu_is_omap24xx())
src = &omap24xx_dss_feats;
- else if (cpu_is_omap34xx())
- src = &omap34xx_dss_feats;
else if (cpu_is_omap3630())
src = &omap3630_dss_feats;
+ else if (cpu_is_omap34xx())
+ src = &omap34xx_dss_feats;
else if (cpu_is_omap44xx())
src = &omap44xx_dss_feats;
else if (soc_is_omap54xx())
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index a48a7dd75b33..8c9b8b3b7f77 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -644,8 +644,10 @@ static void hdmi_dump_regs(struct seq_file *s)
{
mutex_lock(&hdmi.lock);
- if (hdmi_runtime_get())
+ if (hdmi_runtime_get()) {
+ mutex_unlock(&hdmi.lock);
return;
+ }
hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s);
hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s);
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
index 606b89f12351..d630b26a005c 100644
--- a/drivers/video/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -787,7 +787,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
case OMAPFB_WAITFORVSYNC:
DBG("ioctl WAITFORVSYNC\n");
- if (!display && !display->output && !display->output->manager) {
+ if (!display || !display->output || !display->output->manager) {
r = -EINVAL;
break;
}
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 8adb9cc267f9..71f5c459b088 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -361,13 +361,13 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
down_write(&mm->mmap_sem);
vma = find_vma(mm, m.addr);
- ret = -EINVAL;
if (!vma ||
vma->vm_ops != &privcmd_vm_ops ||
(m.addr != vma->vm_start) ||
((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
!privcmd_enforce_singleshot_mapping(vma)) {
up_write(&mm->mmap_sem);
+ ret = -EINVAL;
goto out;
}
@@ -383,12 +383,16 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
up_write(&mm->mmap_sem);
- if (state.global_error && (version == 1)) {
- /* Write back errors in second pass. */
- state.user_mfn = (xen_pfn_t *)m.arr;
- state.err = err_array;
- ret = traverse_pages(m.num, sizeof(xen_pfn_t),
- &pagelist, mmap_return_errors_v1, &state);
+ if (version == 1) {
+ if (state.global_error) {
+ /* Write back errors in second pass. */
+ state.user_mfn = (xen_pfn_t *)m.arr;
+ state.err = err_array;
+ ret = traverse_pages(m.num, sizeof(xen_pfn_t),
+ &pagelist, mmap_return_errors_v1, &state);
+ } else
+ ret = 0;
+
} else if (version == 2) {
ret = __copy_to_user(m.err, err_array, m.num * sizeof(int));
if (ret)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 1a1e5e3b1eaf..ab3a456f6650 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -70,19 +70,6 @@ static void bdev_inode_switch_bdi(struct inode *inode,
spin_unlock(&dst->wb.list_lock);
}
-sector_t blkdev_max_block(struct block_device *bdev)
-{
- sector_t retval = ~((sector_t)0);
- loff_t sz = i_size_read(bdev->bd_inode);
-
- if (sz) {
- unsigned int size = block_size(bdev);
- unsigned int sizebits = blksize_bits(size);
- retval = (sz >> sizebits);
- }
- return retval;
-}
-
/* Kill _all_ buffers and pagecache , dirty or not.. */
void kill_bdev(struct block_device *bdev)
{
@@ -116,8 +103,6 @@ EXPORT_SYMBOL(invalidate_bdev);
int set_blocksize(struct block_device *bdev, int size)
{
- struct address_space *mapping;
-
/* Size must be a power of two, and between 512 and PAGE_SIZE */
if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size))
return -EINVAL;
@@ -126,19 +111,6 @@ int set_blocksize(struct block_device *bdev, int size)
if (size < bdev_logical_block_size(bdev))
return -EINVAL;
- /* Prevent starting I/O or mapping the device */
- percpu_down_write(&bdev->bd_block_size_semaphore);
-
- /* Check that the block device is not memory mapped */
- mapping = bdev->bd_inode->i_mapping;
- mutex_lock(&mapping->i_mmap_mutex);
- if (mapping_mapped(mapping)) {
- mutex_unlock(&mapping->i_mmap_mutex);
- percpu_up_write(&bdev->bd_block_size_semaphore);
- return -EBUSY;
- }
- mutex_unlock(&mapping->i_mmap_mutex);
-
/* Don't change the size if it is same as current */
if (bdev->bd_block_size != size) {
sync_blockdev(bdev);
@@ -146,9 +118,6 @@ int set_blocksize(struct block_device *bdev, int size)
bdev->bd_inode->i_blkbits = blksize_bits(size);
kill_bdev(bdev);
}
-
- percpu_up_write(&bdev->bd_block_size_semaphore);
-
return 0;
}
@@ -181,52 +150,12 @@ static int
blkdev_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh, int create)
{
- if (iblock >= blkdev_max_block(I_BDEV(inode))) {
- if (create)
- return -EIO;
-
- /*
- * for reads, we're just trying to fill a partial page.
- * return a hole, they will have to call get_block again
- * before they can fill it, and they will get -EIO at that
- * time
- */
- return 0;
- }
bh->b_bdev = I_BDEV(inode);
bh->b_blocknr = iblock;
set_buffer_mapped(bh);
return 0;
}
-static int
-blkdev_get_blocks(struct inode *inode, sector_t iblock,
- struct buffer_head *bh, int create)
-{
- sector_t end_block = blkdev_max_block(I_BDEV(inode));
- unsigned long max_blocks = bh->b_size >> inode->i_blkbits;
-
- if ((iblock + max_blocks) > end_block) {
- max_blocks = end_block - iblock;
- if ((long)max_blocks <= 0) {
- if (create)
- return -EIO; /* write fully beyond EOF */
- /*
- * It is a read which is fully beyond EOF. We return
- * a !buffer_mapped buffer
- */
- max_blocks = 0;
- }
- }
-
- bh->b_bdev = I_BDEV(inode);
- bh->b_blocknr = iblock;
- bh->b_size = max_blocks << inode->i_blkbits;
- if (max_blocks)
- set_buffer_mapped(bh);
- return 0;
-}
-
static ssize_t
blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
loff_t offset, unsigned long nr_segs)
@@ -235,7 +164,7 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
struct inode *inode = file->f_mapping->host;
return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
- nr_segs, blkdev_get_blocks, NULL, NULL, 0);
+ nr_segs, blkdev_get_block, NULL, NULL, 0);
}
int __sync_blockdev(struct block_device *bdev, int wait)
@@ -459,12 +388,6 @@ static struct inode *bdev_alloc_inode(struct super_block *sb)
struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL);
if (!ei)
return NULL;
-
- if (unlikely(percpu_init_rwsem(&ei->bdev.bd_block_size_semaphore))) {
- kmem_cache_free(bdev_cachep, ei);
- return NULL;
- }
-
return &ei->vfs_inode;
}
@@ -473,8 +396,6 @@ static void bdev_i_callback(struct rcu_head *head)
struct inode *inode = container_of(head, struct inode, i_rcu);
struct bdev_inode *bdi = BDEV_I(inode);
- percpu_free_rwsem(&bdi->bdev.bd_block_size_semaphore);
-
kmem_cache_free(bdev_cachep, bdi);
}
@@ -1593,22 +1514,6 @@ static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return blkdev_ioctl(bdev, mode, cmd, arg);
}
-ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
-{
- ssize_t ret;
- struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
-
- percpu_down_read(&bdev->bd_block_size_semaphore);
-
- ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
-
- percpu_up_read(&bdev->bd_block_size_semaphore);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(blkdev_aio_read);
-
/*
* Write data to the block device. Only intended for the block device itself
* and the raw driver which basically is a fake block device.
@@ -1620,16 +1525,12 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
- struct block_device *bdev = I_BDEV(file->f_mapping->host);
struct blk_plug plug;
ssize_t ret;
BUG_ON(iocb->ki_pos != pos);
blk_start_plug(&plug);
-
- percpu_down_read(&bdev->bd_block_size_semaphore);
-
ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
if (ret > 0 || ret == -EIOCBQUEUED) {
ssize_t err;
@@ -1638,62 +1539,27 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
if (err < 0 && ret > 0)
ret = err;
}
-
- percpu_up_read(&bdev->bd_block_size_semaphore);
-
blk_finish_plug(&plug);
-
return ret;
}
EXPORT_SYMBOL_GPL(blkdev_aio_write);
-static int blkdev_mmap(struct file *file, struct vm_area_struct *vma)
-{
- int ret;
- struct block_device *bdev = I_BDEV(file->f_mapping->host);
-
- percpu_down_read(&bdev->bd_block_size_semaphore);
-
- ret = generic_file_mmap(file, vma);
-
- percpu_up_read(&bdev->bd_block_size_semaphore);
-
- return ret;
-}
-
-static ssize_t blkdev_splice_read(struct file *file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags)
-{
- ssize_t ret;
- struct block_device *bdev = I_BDEV(file->f_mapping->host);
-
- percpu_down_read(&bdev->bd_block_size_semaphore);
-
- ret = generic_file_splice_read(file, ppos, pipe, len, flags);
-
- percpu_up_read(&bdev->bd_block_size_semaphore);
-
- return ret;
-}
-
-static ssize_t blkdev_splice_write(struct pipe_inode_info *pipe,
- struct file *file, loff_t *ppos, size_t len,
- unsigned int flags)
+static ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
- ssize_t ret;
- struct block_device *bdev = I_BDEV(file->f_mapping->host);
-
- percpu_down_read(&bdev->bd_block_size_semaphore);
-
- ret = generic_file_splice_write(pipe, file, ppos, len, flags);
+ struct file *file = iocb->ki_filp;
+ struct inode *bd_inode = file->f_mapping->host;
+ loff_t size = i_size_read(bd_inode);
- percpu_up_read(&bdev->bd_block_size_semaphore);
+ if (pos >= size)
+ return 0;
- return ret;
+ size -= pos;
+ if (size < INT_MAX)
+ nr_segs = iov_shorten((struct iovec *)iov, nr_segs, size);
+ return generic_file_aio_read(iocb, iov, nr_segs, pos);
}
-
/*
* Try to release a page associated with block device when the system
* is under memory pressure.
@@ -1724,16 +1590,16 @@ const struct file_operations def_blk_fops = {
.llseek = block_llseek,
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = blkdev_aio_read,
+ .aio_read = blkdev_aio_read,
.aio_write = blkdev_aio_write,
- .mmap = blkdev_mmap,
+ .mmap = generic_file_mmap,
.fsync = blkdev_fsync,
.unlocked_ioctl = block_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_blkdev_ioctl,
#endif
- .splice_read = blkdev_splice_read,
- .splice_write = blkdev_splice_write,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
};
int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
diff --git a/fs/buffer.c b/fs/buffer.c
index b5f044283edb..ec0aca8ba6bf 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -911,6 +911,18 @@ link_dev_buffers(struct page *page, struct buffer_head *head)
attach_page_buffers(page, head);
}
+static sector_t blkdev_max_block(struct block_device *bdev, unsigned int size)
+{
+ sector_t retval = ~((sector_t)0);
+ loff_t sz = i_size_read(bdev->bd_inode);
+
+ if (sz) {
+ unsigned int sizebits = blksize_bits(size);
+ retval = (sz >> sizebits);
+ }
+ return retval;
+}
+
/*
* Initialise the state of a blockdev page's buffers.
*/
@@ -921,7 +933,7 @@ init_page_buffers(struct page *page, struct block_device *bdev,
struct buffer_head *head = page_buffers(page);
struct buffer_head *bh = head;
int uptodate = PageUptodate(page);
- sector_t end_block = blkdev_max_block(I_BDEV(bdev->bd_inode));
+ sector_t end_block = blkdev_max_block(I_BDEV(bdev->bd_inode), size);
do {
if (!buffer_mapped(bh)) {
@@ -1553,6 +1565,28 @@ void unmap_underlying_metadata(struct block_device *bdev, sector_t block)
EXPORT_SYMBOL(unmap_underlying_metadata);
/*
+ * Size is a power-of-two in the range 512..PAGE_SIZE,
+ * and the case we care about most is PAGE_SIZE.
+ *
+ * So this *could* possibly be written with those
+ * constraints in mind (relevant mostly if some
+ * architecture has a slow bit-scan instruction)
+ */
+static inline int block_size_bits(unsigned int blocksize)
+{
+ return ilog2(blocksize);
+}
+
+static struct buffer_head *create_page_buffers(struct page *page, struct inode *inode, unsigned int b_state)
+{
+ BUG_ON(!PageLocked(page));
+
+ if (!page_has_buffers(page))
+ create_empty_buffers(page, 1 << ACCESS_ONCE(inode->i_blkbits), b_state);
+ return page_buffers(page);
+}
+
+/*
* NOTE! All mapped/uptodate combinations are valid:
*
* Mapped Uptodate Meaning
@@ -1589,19 +1623,13 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
sector_t block;
sector_t last_block;
struct buffer_head *bh, *head;
- const unsigned blocksize = 1 << inode->i_blkbits;
+ unsigned int blocksize, bbits;
int nr_underway = 0;
int write_op = (wbc->sync_mode == WB_SYNC_ALL ?
WRITE_SYNC : WRITE);
- BUG_ON(!PageLocked(page));
-
- last_block = (i_size_read(inode) - 1) >> inode->i_blkbits;
-
- if (!page_has_buffers(page)) {
- create_empty_buffers(page, blocksize,
+ head = create_page_buffers(page, inode,
(1 << BH_Dirty)|(1 << BH_Uptodate));
- }
/*
* Be very careful. We have no exclusion from __set_page_dirty_buffers
@@ -1613,9 +1641,12 @@ static int __block_write_full_page(struct inode *inode, struct page *page,
* handle that here by just cleaning them.
*/
- block = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
- head = page_buffers(page);
bh = head;
+ blocksize = bh->b_size;
+ bbits = block_size_bits(blocksize);
+
+ block = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits);
+ last_block = (i_size_read(inode) - 1) >> bbits;
/*
* Get all the dirty buffers mapped to disk addresses and
@@ -1806,12 +1837,10 @@ int __block_write_begin(struct page *page, loff_t pos, unsigned len,
BUG_ON(to > PAGE_CACHE_SIZE);
BUG_ON(from > to);
- blocksize = 1 << inode->i_blkbits;
- if (!page_has_buffers(page))
- create_empty_buffers(page, blocksize, 0);
- head = page_buffers(page);
+ head = create_page_buffers(page, inode, 0);
+ blocksize = head->b_size;
+ bbits = block_size_bits(blocksize);
- bbits = inode->i_blkbits;
block = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits);
for(bh = head, block_start = 0; bh != head || !block_start;
@@ -1881,11 +1910,11 @@ static int __block_commit_write(struct inode *inode, struct page *page,
unsigned blocksize;
struct buffer_head *bh, *head;
- blocksize = 1 << inode->i_blkbits;
+ bh = head = page_buffers(page);
+ blocksize = bh->b_size;
- for(bh = head = page_buffers(page), block_start = 0;
- bh != head || !block_start;
- block_start=block_end, bh = bh->b_this_page) {
+ block_start = 0;
+ do {
block_end = block_start + blocksize;
if (block_end <= from || block_start >= to) {
if (!buffer_uptodate(bh))
@@ -1895,7 +1924,10 @@ static int __block_commit_write(struct inode *inode, struct page *page,
mark_buffer_dirty(bh);
}
clear_buffer_new(bh);
- }
+
+ block_start = block_end;
+ bh = bh->b_this_page;
+ } while (bh != head);
/*
* If this is a partial write which happened to make all buffers
@@ -2020,7 +2052,6 @@ EXPORT_SYMBOL(generic_write_end);
int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc,
unsigned long from)
{
- struct inode *inode = page->mapping->host;
unsigned block_start, block_end, blocksize;
unsigned to;
struct buffer_head *bh, *head;
@@ -2029,13 +2060,13 @@ int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc,
if (!page_has_buffers(page))
return 0;
- blocksize = 1 << inode->i_blkbits;
+ head = page_buffers(page);
+ blocksize = head->b_size;
to = min_t(unsigned, PAGE_CACHE_SIZE - from, desc->count);
to = from + to;
if (from < blocksize && to > PAGE_CACHE_SIZE - blocksize)
return 0;
- head = page_buffers(page);
bh = head;
block_start = 0;
do {
@@ -2068,18 +2099,16 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
struct inode *inode = page->mapping->host;
sector_t iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
- unsigned int blocksize;
+ unsigned int blocksize, bbits;
int nr, i;
int fully_mapped = 1;
- BUG_ON(!PageLocked(page));
- blocksize = 1 << inode->i_blkbits;
- if (!page_has_buffers(page))
- create_empty_buffers(page, blocksize, 0);
- head = page_buffers(page);
+ head = create_page_buffers(page, inode, 0);
+ blocksize = head->b_size;
+ bbits = block_size_bits(blocksize);
- iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT - inode->i_blkbits);
- lblock = (i_size_read(inode)+blocksize-1) >> inode->i_blkbits;
+ iblock = (sector_t)page->index << (PAGE_CACHE_SHIFT - bbits);
+ lblock = (i_size_read(inode)+blocksize-1) >> bbits;
bh = head;
nr = 0;
i = 0;
@@ -2864,6 +2893,55 @@ static void end_bio_bh_io_sync(struct bio *bio, int err)
bio_put(bio);
}
+/*
+ * This allows us to do IO even on the odd last sectors
+ * of a device, even if the bh block size is some multiple
+ * of the physical sector size.
+ *
+ * We'll just truncate the bio to the size of the device,
+ * and clear the end of the buffer head manually.
+ *
+ * Truly out-of-range accesses will turn into actual IO
+ * errors, this only handles the "we need to be able to
+ * do IO at the final sector" case.
+ */
+static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh)
+{
+ sector_t maxsector;
+ unsigned bytes;
+
+ maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
+ if (!maxsector)
+ return;
+
+ /*
+ * If the *whole* IO is past the end of the device,
+ * let it through, and the IO layer will turn it into
+ * an EIO.
+ */
+ if (unlikely(bio->bi_sector >= maxsector))
+ return;
+
+ maxsector -= bio->bi_sector;
+ bytes = bio->bi_size;
+ if (likely((bytes >> 9) <= maxsector))
+ return;
+
+ /* Uhhuh. We've got a bh that straddles the device size! */
+ bytes = maxsector << 9;
+
+ /* Truncate the bio.. */
+ bio->bi_size = bytes;
+ bio->bi_io_vec[0].bv_len = bytes;
+
+ /* ..and clear the end of the buffer for reads */
+ if ((rw & RW_MASK) == READ) {
+ void *kaddr = kmap_atomic(bh->b_page);
+ memset(kaddr + bh_offset(bh) + bytes, 0, bh->b_size - bytes);
+ kunmap_atomic(kaddr);
+ }
+}
+
int submit_bh(int rw, struct buffer_head * bh)
{
struct bio *bio;
@@ -2900,6 +2978,9 @@ int submit_bh(int rw, struct buffer_head * bh)
bio->bi_end_io = end_bio_bh_io_sync;
bio->bi_private = bh;
+ /* Take care of bh's that straddle the end of the device */
+ guard_bh_eod(rw, bio, bh);
+
bio_get(bio);
submit_bio(rw, bio);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index edb25b4bbb95..70b6f4c3a0c1 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1794,7 +1794,6 @@ static int cifs_writepages(struct address_space *mapping,
struct TCP_Server_Info *server;
struct page *page;
int rc = 0;
- loff_t isize = i_size_read(mapping->host);
/*
* If wsize is smaller than the page cache size, default to writing
@@ -1899,7 +1898,7 @@ retry:
*/
set_page_writeback(page);
- if (page_offset(page) >= isize) {
+ if (page_offset(page) >= i_size_read(mapping->host)) {
done = true;
unlock_page(page);
end_page_writeback(page);
@@ -1932,7 +1931,8 @@ retry:
wdata->offset = page_offset(wdata->pages[0]);
wdata->pagesz = PAGE_CACHE_SIZE;
wdata->tailsz =
- min(isize - page_offset(wdata->pages[nr_pages - 1]),
+ min(i_size_read(mapping->host) -
+ page_offset(wdata->pages[nr_pages - 1]),
(loff_t)PAGE_CACHE_SIZE);
wdata->bytes = ((nr_pages - 1) * PAGE_CACHE_SIZE) +
wdata->tailsz;
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index f9b5d3d6cf33..1c576e871366 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -86,14 +86,17 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name,
dentry = d_lookup(parent, name);
if (dentry) {
+ int err;
inode = dentry->d_inode;
/* update inode in place if i_ino didn't change */
if (inode && CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
cifs_fattr_to_inode(inode, fattr);
return dentry;
}
- d_drop(dentry);
+ err = d_invalidate(dentry);
dput(dentry);
+ if (err)
+ return NULL;
}
dentry = d_alloc(parent, name);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 56cc4be87807..34cea2798333 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -766,7 +766,6 @@ smb_set_file_info(struct inode *inode, const char *full_path,
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon;
- FILE_BASIC_INFO info_buf;
/* if the file is already open for write, just use that fileid */
open_file = find_writable_file(cinode, true);
@@ -817,7 +816,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
netpid = current->tgid;
set_via_filehandle:
- rc = CIFSSMBSetFileInfo(xid, tcon, &info_buf, netfid, netpid);
+ rc = CIFSSMBSetFileInfo(xid, tcon, buf, netfid, netpid);
if (!rc)
cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index f86c720dba0e..cf5b44b10c67 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -540,6 +540,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
sector_t fs_endblk; /* Into file, in filesystem-sized blocks */
unsigned long fs_count; /* Number of filesystem-sized blocks */
int create;
+ unsigned int i_blkbits = sdio->blkbits + sdio->blkfactor;
/*
* If there was a memory error and we've overwritten all the
@@ -554,7 +555,7 @@ static int get_more_blocks(struct dio *dio, struct dio_submit *sdio,
fs_count = fs_endblk - fs_startblk + 1;
map_bh->b_state = 0;
- map_bh->b_size = fs_count << dio->inode->i_blkbits;
+ map_bh->b_size = fs_count << i_blkbits;
/*
* For writes inside i_size on a DIO_SKIP_HOLES filesystem we
@@ -1053,7 +1054,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
int seg;
size_t size;
unsigned long addr;
- unsigned blkbits = inode->i_blkbits;
+ unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits);
+ unsigned blkbits = i_blkbits;
unsigned blocksize_mask = (1 << blkbits) - 1;
ssize_t retval = -EINVAL;
loff_t end = offset;
@@ -1149,7 +1151,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
dio->inode = inode;
dio->rw = rw;
sdio.blkbits = blkbits;
- sdio.blkfactor = inode->i_blkbits - blkbits;
+ sdio.blkfactor = i_blkbits - blkbits;
sdio.block_in_file = offset >> blkbits;
sdio.get_block = get_block;
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 7320a66e958f..22548f56197b 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -2101,8 +2101,9 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
end = start + (range->len >> sb->s_blocksize_bits) - 1;
minlen = range->minlen >> sb->s_blocksize_bits;
- if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)) ||
- unlikely(start >= max_blks))
+ if (minlen > EXT3_BLOCKS_PER_GROUP(sb) ||
+ start >= max_blks ||
+ range->len < sb->s_blocksize)
return -EINVAL;
if (end >= max_blks)
end = max_blks - 1;
diff --git a/fs/file.c b/fs/file.c
index 708d997a7748..eff23162485f 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -685,7 +685,6 @@ void do_close_on_exec(struct files_struct *files)
struct fdtable *fdt;
/* exec unshares first */
- BUG_ON(atomic_read(&files->count) != 1);
spin_lock(&files->file_lock);
for (i = 0; ; i++) {
unsigned long set;
@@ -995,16 +994,18 @@ int iterate_fd(struct files_struct *files, unsigned n,
const void *p)
{
struct fdtable *fdt;
- struct file *file;
int res = 0;
if (!files)
return 0;
spin_lock(&files->file_lock);
- fdt = files_fdtable(files);
- while (!res && n < fdt->max_fds) {
- file = rcu_dereference_check_fdtable(files, fdt->fd[n++]);
- if (file)
- res = f(p, file, n);
+ for (fdt = files_fdtable(files); n < fdt->max_fds; n++) {
+ struct file *file;
+ file = rcu_dereference_check_fdtable(files, fdt->fd[n]);
+ if (!file)
+ continue;
+ res = f(p, file, n);
+ if (res)
+ break;
}
spin_unlock(&files->file_lock);
return res;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 51ea267d444c..3e3422f7f0a4 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -228,6 +228,8 @@ static void requeue_io(struct inode *inode, struct bdi_writeback *wb)
static void inode_sync_complete(struct inode *inode)
{
inode->i_state &= ~I_SYNC;
+ /* If inode is clean an unused, put it into LRU now... */
+ inode_add_lru(inode);
/* Waiters must see I_SYNC cleared before being woken up */
smp_mb();
wake_up_bit(&inode->i_state, __I_SYNC);
diff --git a/fs/inode.c b/fs/inode.c
index b03c71957246..64999f144153 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -408,6 +408,19 @@ static void inode_lru_list_add(struct inode *inode)
spin_unlock(&inode->i_sb->s_inode_lru_lock);
}
+/*
+ * Add inode to LRU if needed (inode is unused and clean).
+ *
+ * Needs inode->i_lock held.
+ */
+void inode_add_lru(struct inode *inode)
+{
+ if (!(inode->i_state & (I_DIRTY | I_SYNC | I_FREEING | I_WILL_FREE)) &&
+ !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE)
+ inode_lru_list_add(inode);
+}
+
+
static void inode_lru_list_del(struct inode *inode)
{
spin_lock(&inode->i_sb->s_inode_lru_lock);
@@ -1390,8 +1403,7 @@ static void iput_final(struct inode *inode)
if (!drop && (sb->s_flags & MS_ACTIVE)) {
inode->i_state |= I_REFERENCED;
- if (!(inode->i_state & (I_DIRTY|I_SYNC)))
- inode_lru_list_add(inode);
+ inode_add_lru(inode);
spin_unlock(&inode->i_lock);
return;
}
diff --git a/fs/internal.h b/fs/internal.h
index 916b7cbf3e3e..2f6af7f645eb 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -110,6 +110,7 @@ extern int open_check_o_direct(struct file *f);
* inode.c
*/
extern spinlock_t inode_sb_list_lock;
+extern void inode_add_lru(struct inode *inode);
/*
* fs-writeback.c
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 78b7f84241d4..7f5120bf0ec2 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1961,7 +1961,9 @@ retry:
spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh);
spin_unlock(&journal->j_state_lock);
+ unlock_buffer(bh);
log_wait_commit(journal, tid);
+ lock_buffer(bh);
goto retry;
}
/*
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 60ef3fb707ff..1506673c087e 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -138,33 +138,39 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
struct page *pg;
struct inode *inode = mapping->host;
struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_raw_inode ri;
+ uint32_t alloc_len = 0;
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
uint32_t pageofs = index << PAGE_CACHE_SHIFT;
int ret = 0;
+ jffs2_dbg(1, "%s()\n", __func__);
+
+ if (pageofs > inode->i_size) {
+ ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
+ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
+ if (ret)
+ return ret;
+ }
+
+ mutex_lock(&f->sem);
pg = grab_cache_page_write_begin(mapping, index, flags);
- if (!pg)
+ if (!pg) {
+ if (alloc_len)
+ jffs2_complete_reservation(c);
+ mutex_unlock(&f->sem);
return -ENOMEM;
+ }
*pagep = pg;
- jffs2_dbg(1, "%s()\n", __func__);
-
- if (pageofs > inode->i_size) {
+ if (alloc_len) {
/* Make new hole frag from old EOF to new page */
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- struct jffs2_raw_inode ri;
struct jffs2_full_dnode *fn;
- uint32_t alloc_len;
jffs2_dbg(1, "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
(unsigned int)inode->i_size, pageofs);
- ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
- ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
- if (ret)
- goto out_page;
-
- mutex_lock(&f->sem);
memset(&ri, 0, sizeof(ri));
ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
@@ -191,7 +197,6 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
if (IS_ERR(fn)) {
ret = PTR_ERR(fn);
jffs2_complete_reservation(c);
- mutex_unlock(&f->sem);
goto out_page;
}
ret = jffs2_add_full_dnode_to_inode(c, f, fn);
@@ -206,12 +211,10 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
jffs2_mark_node_obsolete(c, fn->raw);
jffs2_free_full_dnode(fn);
jffs2_complete_reservation(c);
- mutex_unlock(&f->sem);
goto out_page;
}
jffs2_complete_reservation(c);
inode->i_size = pageofs;
- mutex_unlock(&f->sem);
}
/*
@@ -220,18 +223,18 @@ static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
* case of a short-copy.
*/
if (!PageUptodate(pg)) {
- mutex_lock(&f->sem);
ret = jffs2_do_readpage_nolock(inode, pg);
- mutex_unlock(&f->sem);
if (ret)
goto out_page;
}
+ mutex_unlock(&f->sem);
jffs2_dbg(1, "end write_begin(). pg->flags %lx\n", pg->flags);
return ret;
out_page:
unlock_page(pg);
page_cache_release(pg);
+ mutex_unlock(&f->sem);
return ret;
}
diff --git a/fs/namei.c b/fs/namei.c
index 937f9d50c84b..5f4cdf3ad913 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2131,6 +2131,11 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
if (!len)
return ERR_PTR(-EACCES);
+ if (unlikely(name[0] == '.')) {
+ if (len < 2 || (len == 2 && name[1] == '.'))
+ return ERR_PTR(-EACCES);
+ }
+
while (len--) {
c = *(const unsigned char *)name++;
if (c == '/' || c == '\0')
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index ce8cb926526b..b9e66b7e0c14 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -450,7 +450,8 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
nfs_refresh_inode(dentry->d_inode, entry->fattr);
goto out;
} else {
- d_drop(dentry);
+ if (d_invalidate(dentry) != 0)
+ goto out;
dput(dentry);
}
}
@@ -1100,6 +1101,8 @@ out_set_verifier:
out_zap_parent:
nfs_zap_caches(dir);
out_bad:
+ nfs_free_fattr(fattr);
+ nfs_free_fhandle(fhandle);
nfs_mark_for_revalidate(dir);
if (inode && S_ISDIR(inode->i_mode)) {
/* Purge readdir caches. */
@@ -1112,8 +1115,6 @@ out_zap_parent:
shrink_dcache_parent(dentry);
}
d_drop(dentry);
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fhandle);
dput(parent);
dfprintk(LOOKUPCACHE, "NFS: %s(%s/%s) is invalid\n",
__func__, dentry->d_parent->d_name.name,
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
index 721d692fa8d4..6fcaeb8c902e 100644
--- a/fs/notify/fanotify/fanotify_user.c
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -258,7 +258,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
if (ret)
goto out_close_fd;
- fd_install(fd, f);
+ if (fd != FAN_NOFD)
+ fd_install(fd, f);
return fanotify_event_metadata.event_len;
out_close_fd:
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 144a96732dd7..9e28356a959a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -873,6 +873,113 @@ static const struct file_operations proc_environ_operations = {
.release = mem_release,
};
+static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode);
+ char buffer[PROC_NUMBUF];
+ int oom_adj = OOM_ADJUST_MIN;
+ size_t len;
+ unsigned long flags;
+
+ if (!task)
+ return -ESRCH;
+ if (lock_task_sighand(task, &flags)) {
+ if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
+ oom_adj = OOM_ADJUST_MAX;
+ else
+ oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
+ OOM_SCORE_ADJ_MAX;
+ unlock_task_sighand(task, &flags);
+ }
+ put_task_struct(task);
+ len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj);
+ return simple_read_from_buffer(buf, count, ppos, buffer, len);
+}
+
+static ssize_t oom_adj_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF];
+ int oom_adj;
+ unsigned long flags;
+ int err;
+
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count)) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ err = kstrtoint(strstrip(buffer), 0, &oom_adj);
+ if (err)
+ goto out;
+ if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) &&
+ oom_adj != OOM_DISABLE) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ task = get_proc_task(file->f_path.dentry->d_inode);
+ if (!task) {
+ err = -ESRCH;
+ goto out;
+ }
+
+ task_lock(task);
+ if (!task->mm) {
+ err = -EINVAL;
+ goto err_task_lock;
+ }
+
+ if (!lock_task_sighand(task, &flags)) {
+ err = -ESRCH;
+ goto err_task_lock;
+ }
+
+ /*
+ * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
+ * value is always attainable.
+ */
+ if (oom_adj == OOM_ADJUST_MAX)
+ oom_adj = OOM_SCORE_ADJ_MAX;
+ else
+ oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
+
+ if (oom_adj < task->signal->oom_score_adj &&
+ !capable(CAP_SYS_RESOURCE)) {
+ err = -EACCES;
+ goto err_sighand;
+ }
+
+ /*
+ * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
+ * /proc/pid/oom_score_adj instead.
+ */
+ printk_once(KERN_WARNING "%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
+ current->comm, task_pid_nr(current), task_pid_nr(task),
+ task_pid_nr(task));
+
+ task->signal->oom_score_adj = oom_adj;
+ trace_oom_score_adj_update(task);
+err_sighand:
+ unlock_task_sighand(task, &flags);
+err_task_lock:
+ task_unlock(task);
+ put_task_struct(task);
+out:
+ return err < 0 ? err : count;
+}
+
+static const struct file_operations proc_oom_adj_operations = {
+ .read = oom_adj_read,
+ .write = oom_adj_write,
+ .llseek = generic_file_llseek,
+};
+
static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -1770,8 +1877,9 @@ static struct dentry *proc_map_files_lookup(struct inode *dir,
if (!vma)
goto out_no_vma;
- result = proc_map_files_instantiate(dir, dentry, task,
- (void *)(unsigned long)vma->vm_file->f_mode);
+ if (vma->vm_file)
+ result = proc_map_files_instantiate(dir, dentry, task,
+ (void *)(unsigned long)vma->vm_file->f_mode);
out_no_vma:
up_read(&mm->mmap_sem);
@@ -2598,6 +2706,7 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("cgroup", S_IRUGO, proc_cgroup_operations),
#endif
INF("oom_score", S_IRUGO, proc_oom_score),
+ REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
@@ -2964,6 +3073,7 @@ static const struct pid_entry tid_base_stuff[] = {
REG("cgroup", S_IRUGO, proc_cgroup_operations),
#endif
INF("oom_score", S_IRUGO, proc_oom_score),
+ REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index a40da07e93d6..947fbe06c3b1 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -161,6 +161,7 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c)
while (s < e) {
unsigned long flags;
+ u64 id;
if (c > psinfo->bufsize)
c = psinfo->bufsize;
@@ -172,7 +173,7 @@ static void pstore_console_write(struct console *con, const char *s, unsigned c)
spin_lock_irqsave(&psinfo->buf_lock, flags);
}
memcpy(psinfo->buf, s, c);
- psinfo->write(PSTORE_TYPE_CONSOLE, 0, NULL, 0, c, psinfo);
+ psinfo->write(PSTORE_TYPE_CONSOLE, 0, &id, 0, c, psinfo);
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
s += c;
c = e - s;
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index f27f01a98aa2..d83736fbc26c 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1782,8 +1782,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
BUG_ON(!th->t_trans_id);
- dquot_initialize(inode);
+ reiserfs_write_unlock(inode->i_sb);
err = dquot_alloc_inode(inode);
+ reiserfs_write_lock(inode->i_sb);
if (err)
goto out_end_trans;
if (!dir->i_nlink) {
@@ -1979,8 +1980,10 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
out_end_trans:
journal_end(th, th->t_super, th->t_blocks_allocated);
+ reiserfs_write_unlock(inode->i_sb);
/* Drop can be outside and it needs more credits so it's better to have it outside */
dquot_drop(inode);
+ reiserfs_write_lock(inode->i_sb);
inode->i_flags |= S_NOQUOTA;
make_bad_inode(inode);
@@ -3103,10 +3106,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
/* must be turned off for recursive notify_change calls */
ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
- depth = reiserfs_write_lock_once(inode->i_sb);
if (is_quota_modification(inode, attr))
dquot_initialize(inode);
-
+ depth = reiserfs_write_lock_once(inode->i_sb);
if (attr->ia_valid & ATTR_SIZE) {
/* version 2 items will be caught by the s_maxbytes check
** done for us in vmtruncate
@@ -3170,7 +3172,9 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
error = journal_begin(&th, inode->i_sb, jbegin_count);
if (error)
goto out;
+ reiserfs_write_unlock_once(inode->i_sb, depth);
error = dquot_transfer(inode, attr);
+ depth = reiserfs_write_lock_once(inode->i_sb);
if (error) {
journal_end(&th, inode->i_sb, jbegin_count);
goto out;
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index f8afa4b162b8..2f40a4c70a4d 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -1968,7 +1968,9 @@ int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct tree
key2type(&(key->on_disk_key)));
#endif
+ reiserfs_write_unlock(inode->i_sb);
retval = dquot_alloc_space_nodirty(inode, pasted_size);
+ reiserfs_write_lock(inode->i_sb);
if (retval) {
pathrelse(search_path);
return retval;
@@ -2061,9 +2063,11 @@ int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
"reiserquota insert_item(): allocating %u id=%u type=%c",
quota_bytes, inode->i_uid, head2type(ih));
#endif
+ reiserfs_write_unlock(inode->i_sb);
/* We can't dirty inode here. It would be immediately written but
* appropriate stat item isn't inserted yet... */
retval = dquot_alloc_space_nodirty(inode, quota_bytes);
+ reiserfs_write_lock(inode->i_sb);
if (retval) {
pathrelse(path);
return retval;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 1078ae179993..418bdc3a57da 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -298,7 +298,9 @@ static int finish_unfinished(struct super_block *s)
retval = remove_save_link_only(s, &save_link_key, 0);
continue;
}
+ reiserfs_write_unlock(s);
dquot_initialize(inode);
+ reiserfs_write_lock(s);
if (truncate && S_ISDIR(inode->i_mode)) {
/* We got a truncate request for a dir which is impossible.
@@ -1335,7 +1337,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
kfree(qf_names[i]);
#endif
err = -EINVAL;
- goto out_err;
+ goto out_unlock;
}
#ifdef CONFIG_QUOTA
handle_quota_files(s, qf_names, &qfmt);
@@ -1379,7 +1381,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
if (blocks) {
err = reiserfs_resize(s, blocks);
if (err != 0)
- goto out_err;
+ goto out_unlock;
}
if (*mount_flags & MS_RDONLY) {
@@ -1389,9 +1391,15 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
/* it is read-only already */
goto out_ok;
+ /*
+ * Drop write lock. Quota will retake it when needed and lock
+ * ordering requires calling dquot_suspend() without it.
+ */
+ reiserfs_write_unlock(s);
err = dquot_suspend(s, -1);
if (err < 0)
goto out_err;
+ reiserfs_write_lock(s);
/* try to remount file system with read-only permissions */
if (sb_umount_state(rs) == REISERFS_VALID_FS
@@ -1401,7 +1409,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
err = journal_begin(&th, s, 10);
if (err)
- goto out_err;
+ goto out_unlock;
/* Mounting a rw partition read-only. */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
@@ -1416,7 +1424,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
if (reiserfs_is_journal_aborted(journal)) {
err = journal->j_errno;
- goto out_err;
+ goto out_unlock;
}
handle_data_mode(s, mount_options);
@@ -1425,7 +1433,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */
err = journal_begin(&th, s, 10);
if (err)
- goto out_err;
+ goto out_unlock;
/* Mount a partition which is read-only, read-write */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
@@ -1442,10 +1450,16 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
SB_JOURNAL(s)->j_must_wait = 1;
err = journal_end(&th, s, 10);
if (err)
- goto out_err;
+ goto out_unlock;
if (!(*mount_flags & MS_RDONLY)) {
+ /*
+ * Drop write lock. Quota will retake it when needed and lock
+ * ordering requires calling dquot_resume() without it.
+ */
+ reiserfs_write_unlock(s);
dquot_resume(s, -1);
+ reiserfs_write_lock(s);
finish_unfinished(s);
reiserfs_xattr_init(s, *mount_flags);
}
@@ -1455,9 +1469,10 @@ out_ok:
reiserfs_write_unlock(s);
return 0;
+out_unlock:
+ reiserfs_write_unlock(s);
out_err:
kfree(new_opts);
- reiserfs_write_unlock(s);
return err;
}
@@ -2095,13 +2110,15 @@ static int reiserfs_write_dquot(struct dquot *dquot)
REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
if (ret)
goto out;
+ reiserfs_write_unlock(dquot->dq_sb);
ret = dquot_commit(dquot);
+ reiserfs_write_lock(dquot->dq_sb);
err =
journal_end(&th, dquot->dq_sb,
REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
if (!ret && err)
ret = err;
- out:
+out:
reiserfs_write_unlock(dquot->dq_sb);
return ret;
}
@@ -2117,13 +2134,15 @@ static int reiserfs_acquire_dquot(struct dquot *dquot)
REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
if (ret)
goto out;
+ reiserfs_write_unlock(dquot->dq_sb);
ret = dquot_acquire(dquot);
+ reiserfs_write_lock(dquot->dq_sb);
err =
journal_end(&th, dquot->dq_sb,
REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
if (!ret && err)
ret = err;
- out:
+out:
reiserfs_write_unlock(dquot->dq_sb);
return ret;
}
@@ -2137,19 +2156,21 @@ static int reiserfs_release_dquot(struct dquot *dquot)
ret =
journal_begin(&th, dquot->dq_sb,
REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+ reiserfs_write_unlock(dquot->dq_sb);
if (ret) {
/* Release dquot anyway to avoid endless cycle in dqput() */
dquot_release(dquot);
goto out;
}
ret = dquot_release(dquot);
+ reiserfs_write_lock(dquot->dq_sb);
err =
journal_end(&th, dquot->dq_sb,
REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
if (!ret && err)
ret = err;
- out:
reiserfs_write_unlock(dquot->dq_sb);
+out:
return ret;
}
@@ -2174,11 +2195,13 @@ static int reiserfs_write_info(struct super_block *sb, int type)
ret = journal_begin(&th, sb, 2);
if (ret)
goto out;
+ reiserfs_write_unlock(sb);
ret = dquot_commit_info(sb, type);
+ reiserfs_write_lock(sb);
err = journal_end(&th, sb, 2);
if (!ret && err)
ret = err;
- out:
+out:
reiserfs_write_unlock(sb);
return ret;
}
@@ -2203,8 +2226,11 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
struct reiserfs_transaction_handle th;
int opt = type == USRQUOTA ? REISERFS_USRQUOTA : REISERFS_GRPQUOTA;
- if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt)))
- return -EINVAL;
+ reiserfs_write_lock(sb);
+ if (!(REISERFS_SB(sb)->s_mount_opt & (1 << opt))) {
+ err = -EINVAL;
+ goto out;
+ }
/* Quotafile not on the same filesystem? */
if (path->dentry->d_sb != sb) {
@@ -2246,8 +2272,10 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
if (err)
goto out;
}
- err = dquot_quota_on(sb, type, format_id, path);
+ reiserfs_write_unlock(sb);
+ return dquot_quota_on(sb, type, format_id, path);
out:
+ reiserfs_write_unlock(sb);
return err;
}
@@ -2320,7 +2348,9 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
tocopy = sb->s_blocksize - offset < towrite ?
sb->s_blocksize - offset : towrite;
tmp_bh.b_state = 0;
+ reiserfs_write_lock(sb);
err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);
+ reiserfs_write_unlock(sb);
if (err)
goto out;
if (offset || tocopy != sb->s_blocksize)
@@ -2336,10 +2366,12 @@ static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
flush_dcache_page(bh->b_page);
set_buffer_uptodate(bh);
unlock_buffer(bh);
+ reiserfs_write_lock(sb);
reiserfs_prepare_for_journal(sb, bh, 1);
journal_mark_dirty(current->journal_info, sb, bh);
if (!journal_quota)
reiserfs_add_ordered_list(inode, bh);
+ reiserfs_write_unlock(sb);
brelse(bh);
offset = 0;
towrite -= tocopy;
diff --git a/fs/ubifs/find.c b/fs/ubifs/find.c
index 28ec13af28d9..2dcf3d473fec 100644
--- a/fs/ubifs/find.c
+++ b/fs/ubifs/find.c
@@ -681,8 +681,16 @@ int ubifs_find_free_leb_for_idx(struct ubifs_info *c)
if (!lprops) {
lprops = ubifs_fast_find_freeable(c);
if (!lprops) {
- ubifs_assert(c->freeable_cnt == 0);
- if (c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) {
+ /*
+ * The first condition means the following: go scan the
+ * LPT if there are uncategorized lprops, which means
+ * there may be freeable LEBs there (UBIFS does not
+ * store the information about freeable LEBs in the
+ * master node).
+ */
+ if (c->in_a_category_cnt != c->main_lebs ||
+ c->lst.empty_lebs - c->lst.taken_empty_lebs > 0) {
+ ubifs_assert(c->freeable_cnt == 0);
lprops = scan_for_leb_for_idx(c);
if (IS_ERR(lprops)) {
err = PTR_ERR(lprops);
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index e5a2a35a46dc..46190a7c42a6 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -300,8 +300,11 @@ void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
default:
ubifs_assert(0);
}
+
lprops->flags &= ~LPROPS_CAT_MASK;
lprops->flags |= cat;
+ c->in_a_category_cnt += 1;
+ ubifs_assert(c->in_a_category_cnt <= c->main_lebs);
}
/**
@@ -334,6 +337,9 @@ static void ubifs_remove_from_cat(struct ubifs_info *c,
default:
ubifs_assert(0);
}
+
+ c->in_a_category_cnt -= 1;
+ ubifs_assert(c->in_a_category_cnt >= 0);
}
/**
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 5486346d0a3f..d133c276fe05 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -1183,6 +1183,8 @@ struct ubifs_debug_info;
* @freeable_list: list of freeable non-index LEBs (free + dirty == @leb_size)
* @frdi_idx_list: list of freeable index LEBs (free + dirty == @leb_size)
* @freeable_cnt: number of freeable LEBs in @freeable_list
+ * @in_a_category_cnt: count of lprops which are in a certain category, which
+ * basically meants that they were loaded from the flash
*
* @ltab_lnum: LEB number of LPT's own lprops table
* @ltab_offs: offset of LPT's own lprops table
@@ -1412,6 +1414,7 @@ struct ubifs_info {
struct list_head freeable_list;
struct list_head frdi_idx_list;
int freeable_cnt;
+ int in_a_category_cnt;
int ltab_lnum;
int ltab_offs;
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index e562dd43f41f..e57e2daa357c 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -481,11 +481,17 @@ static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
*
* The fix is two passes across the ioend list - one to start writeback on the
* buffer_heads, and then submit them for I/O on the second pass.
+ *
+ * If @fail is non-zero, it means that we have a situation where some part of
+ * the submission process has failed after we have marked paged for writeback
+ * and unlocked them. In this situation, we need to fail the ioend chain rather
+ * than submit it to IO. This typically only happens on a filesystem shutdown.
*/
STATIC void
xfs_submit_ioend(
struct writeback_control *wbc,
- xfs_ioend_t *ioend)
+ xfs_ioend_t *ioend,
+ int fail)
{
xfs_ioend_t *head = ioend;
xfs_ioend_t *next;
@@ -506,6 +512,18 @@ xfs_submit_ioend(
next = ioend->io_list;
bio = NULL;
+ /*
+ * If we are failing the IO now, just mark the ioend with an
+ * error and finish it. This will run IO completion immediately
+ * as there is only one reference to the ioend at this point in
+ * time.
+ */
+ if (fail) {
+ ioend->io_error = -fail;
+ xfs_finish_ioend(ioend);
+ continue;
+ }
+
for (bh = ioend->io_buffer_head; bh; bh = bh->b_private) {
if (!bio) {
@@ -1060,7 +1078,18 @@ xfs_vm_writepage(
xfs_start_page_writeback(page, 1, count);
- if (ioend && imap_valid) {
+ /* if there is no IO to be submitted for this page, we are done */
+ if (!ioend)
+ return 0;
+
+ ASSERT(iohead);
+
+ /*
+ * Any errors from this point onwards need tobe reported through the IO
+ * completion path as we have marked the initial page as under writeback
+ * and unlocked it.
+ */
+ if (imap_valid) {
xfs_off_t end_index;
end_index = imap.br_startoff + imap.br_blockcount;
@@ -1079,20 +1108,15 @@ xfs_vm_writepage(
wbc, end_index);
}
- if (iohead) {
- /*
- * Reserve log space if we might write beyond the on-disk
- * inode size.
- */
- if (ioend->io_type != XFS_IO_UNWRITTEN &&
- xfs_ioend_is_append(ioend)) {
- err = xfs_setfilesize_trans_alloc(ioend);
- if (err)
- goto error;
- }
- xfs_submit_ioend(wbc, iohead);
- }
+ /*
+ * Reserve log space if we might write beyond the on-disk inode size.
+ */
+ err = 0;
+ if (ioend->io_type != XFS_IO_UNWRITTEN && xfs_ioend_is_append(ioend))
+ err = xfs_setfilesize_trans_alloc(ioend);
+
+ xfs_submit_ioend(wbc, iohead, err);
return 0;
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index d330111ca738..70eec1829776 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -1291,6 +1291,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
leaf2 = blk2->bp->b_addr;
ASSERT(leaf1->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
ASSERT(leaf2->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC));
+ ASSERT(leaf2->hdr.count == 0);
args = state->args;
trace_xfs_attr_leaf_rebalance(args);
@@ -1361,6 +1362,7 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
* I assert that since all callers pass in an empty
* second buffer, this code should never execute.
*/
+ ASSERT(0);
/*
* Figure the total bytes to be added to the destination leaf.
@@ -1422,10 +1424,24 @@ xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
args->index2 = 0;
args->blkno2 = blk2->blkno;
} else {
+ /*
+ * On a double leaf split, the original attr location
+ * is already stored in blkno2/index2, so don't
+ * overwrite it overwise we corrupt the tree.
+ */
blk2->index = blk1->index
- be16_to_cpu(leaf1->hdr.count);
- args->index = args->index2 = blk2->index;
- args->blkno = args->blkno2 = blk2->blkno;
+ args->index = blk2->index;
+ args->blkno = blk2->blkno;
+ if (!state->extravalid) {
+ /*
+ * set the new attr location to match the old
+ * one and let the higher level split code
+ * decide where in the leaf to place it.
+ */
+ args->index2 = blk2->index;
+ args->blkno2 = blk2->blkno;
+ }
}
} else {
ASSERT(state->inleaf == 1);
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 933b7930b863..4b0b8dd1b7b0 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -1197,9 +1197,14 @@ xfs_buf_bio_end_io(
{
xfs_buf_t *bp = (xfs_buf_t *)bio->bi_private;
- xfs_buf_ioerror(bp, -error);
+ /*
+ * don't overwrite existing errors - otherwise we can lose errors on
+ * buffers that require multiple bios to complete.
+ */
+ if (!bp->b_error)
+ xfs_buf_ioerror(bp, -error);
- if (!error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ))
+ if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ))
invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp));
_xfs_buf_ioend(bp, 1);
@@ -1279,6 +1284,11 @@ next_chunk:
if (size)
goto next_chunk;
} else {
+ /*
+ * This is guaranteed not to be the last io reference count
+ * because the caller (xfs_buf_iorequest) holds a count itself.
+ */
+ atomic_dec(&bp->b_io_remaining);
xfs_buf_ioerror(bp, EIO);
bio_put(bio);
}
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index a9432fc6b8ba..9fd3093d855a 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -5,6 +5,7 @@
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/of.h>
+#include <linux/pinctrl/pinctrl.h>
#ifdef CONFIG_GPIOLIB
@@ -134,6 +135,15 @@ struct gpio_chip {
int (*of_xlate)(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec, u32 *flags);
#endif
+#ifdef CONFIG_PINCTRL
+ /*
+ * If CONFIG_PINCTRL is enabled, then gpio controllers can optionally
+ * describe the actual pin range which they serve in an SoC. This
+ * information would be used by pinctrl subsystem to configure
+ * corresponding pins for gpio usage.
+ */
+ struct list_head pin_ranges;
+#endif
};
extern const char *gpiochip_is_requested(struct gpio_chip *chip,
@@ -257,4 +267,41 @@ static inline void gpio_unexport(unsigned gpio)
}
#endif /* CONFIG_GPIO_SYSFS */
+#ifdef CONFIG_PINCTRL
+
+/**
+ * struct gpio_pin_range - pin range controlled by a gpio chip
+ * @head: list for maintaining set of pin ranges, used internally
+ * @pctldev: pinctrl device which handles corresponding pins
+ * @range: actual range of pins controlled by a gpio controller
+ */
+
+struct gpio_pin_range {
+ struct list_head node;
+ struct pinctrl_dev *pctldev;
+ struct pinctrl_gpio_range range;
+};
+
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int gpio_offset, unsigned int pin_offset,
+ unsigned int npins);
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
+
+#else
+
+static inline int
+gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int gpio_offset, unsigned int pin_offset,
+ unsigned int npins)
+{
+ return 0;
+}
+
+static inline void
+gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+}
+
+#endif /* CONFIG_PINCTRL */
+
#endif /* _ASM_GENERIC_GPIO_H */
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index af1cbaf535ed..c5c35e629426 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -210,6 +210,7 @@
{0x1002, 0x6798, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6799, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
{0x1002, 0x679A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x679B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
{0x1002, 0x679E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
{0x1002, 0x679F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TAHITI|RADEON_NEW_MEMMAP}, \
{0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
diff --git a/include/linux/bug.h b/include/linux/bug.h
index aaac4bba6f5c..b1cf40de847e 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -15,6 +15,7 @@ struct pt_regs;
#define BUILD_BUG_ON_NOT_POWER_OF_2(n)
#define BUILD_BUG_ON_ZERO(e) (0)
#define BUILD_BUG_ON_NULL(e) ((void*)0)
+#define BUILD_BUG_ON_INVALID(e) (0)
#define BUILD_BUG_ON(condition)
#define BUILD_BUG() (0)
#else /* __CHECKER__ */
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c12731582920..4989b8a7bed1 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -53,9 +53,18 @@ struct clk_hw;
* @disable: Disable the clock atomically. Called with enable_lock held.
* This function must not sleep.
*
- * @recalc_rate Recalculate the rate of this clock, by quering hardware. The
+ * @is_enabled: Queries the hardware to determine if the clock is enabled.
+ * This function must not sleep. Optional, if this op is not
+ * set then the enable count will be used.
+ *
+ * @disable_unused: Disable the clock atomically. Only called from
+ * clk_disable_unused for gate clocks with special needs.
+ * Called with enable_lock held. This function must not
+ * sleep.
+ *
+ * @recalc_rate Recalculate the rate of this clock, by querying hardware. The
* parent rate is an input parameter. It is up to the caller to
- * insure that the prepare_mutex is held across this call.
+ * ensure that the prepare_mutex is held across this call.
* Returns the calculated rate. Optional, but recommended - if
* this op is not set then clock rate will be initialized to 0.
*
@@ -89,7 +98,7 @@ struct clk_hw;
* implementations to split any work between atomic (enable) and sleepable
* (prepare) contexts. If enabling a clock requires code that might sleep,
* this must be done in clk_prepare. Clock enable code that will never be
- * called in a sleepable context may be implement in clk_enable.
+ * called in a sleepable context may be implemented in clk_enable.
*
* Typically, drivers will call clk_prepare when a clock may be needed later
* (eg. when a device is opened), and clk_enable when the clock is actually
@@ -102,6 +111,7 @@ struct clk_ops {
int (*enable)(struct clk_hw *hw);
void (*disable)(struct clk_hw *hw);
int (*is_enabled)(struct clk_hw *hw);
+ void (*disable_unused)(struct clk_hw *hw);
unsigned long (*recalc_rate)(struct clk_hw *hw,
unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long,
@@ -327,19 +337,21 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
* error code; drivers must test for an error code after calling clk_register.
*/
struct clk *clk_register(struct device *dev, struct clk_hw *hw);
+struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
void clk_unregister(struct clk *clk);
+void devm_clk_unregister(struct device *dev, struct clk *clk);
/* helper functions */
const char *__clk_get_name(struct clk *clk);
struct clk_hw *__clk_get_hw(struct clk *clk);
u8 __clk_get_num_parents(struct clk *clk);
struct clk *__clk_get_parent(struct clk *clk);
-inline int __clk_get_enable_count(struct clk *clk);
-inline int __clk_get_prepare_count(struct clk *clk);
+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);
-int __clk_is_enabled(struct clk *clk);
+bool __clk_is_enabled(struct clk *clk);
struct clk *__clk_lookup(const char *name);
/*
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 2f303e4b7ed3..01b5c84be828 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -68,7 +68,7 @@ struct device;
extern struct cma *dma_contiguous_default_area;
void dma_contiguous_reserve(phys_addr_t addr_limit);
-int dma_declare_contiguous(struct device *dev, unsigned long size,
+int dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit);
struct page *dma_alloc_from_contiguous(struct device *dev, int count,
@@ -83,7 +83,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
static inline void dma_contiguous_reserve(phys_addr_t limit) { }
static inline
-int dma_declare_contiguous(struct device *dev, unsigned long size,
+int dma_declare_contiguous(struct device *dev, phys_addr_t size,
phys_addr_t base, phys_addr_t limit)
{
return -ENOSYS;
diff --git a/include/linux/edac.h b/include/linux/edac.h
index bab9f8473dc1..1b8c02b36f76 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -533,6 +533,7 @@ struct csrow_info {
u32 ue_count; /* Uncorrectable Errors for this csrow */
u32 ce_count; /* Correctable Errors for this csrow */
+ u32 nr_pages; /* combined pages count of all channels */
struct mem_ctl_info *mci; /* the parent */
@@ -667,6 +668,8 @@ struct mem_ctl_info {
u32 fake_inject_ue;
u16 fake_inject_count;
#endif
+ __u8 csbased : 1, /* csrow-based memory controller */
+ __resv : 7;
};
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b33cfc97b9ca..75fe9a134803 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -462,8 +462,6 @@ struct block_device {
int bd_fsfreeze_count;
/* Mutex for freeze */
struct mutex bd_fsfreeze_mutex;
- /* A semaphore that prevents I/O while block size is being changed */
- struct percpu_rw_semaphore bd_block_size_semaphore;
};
/*
@@ -2049,7 +2047,6 @@ extern void unregister_blkdev(unsigned int, const char *);
extern struct block_device *bdget(dev_t);
extern struct block_device *bdgrab(struct block_device *bdev);
extern void bd_set_size(struct block_device *, loff_t size);
-extern sector_t blkdev_max_block(struct block_device *bdev);
extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
extern void invalidate_bdev(struct block_device *);
@@ -2379,8 +2376,6 @@ extern int generic_segment_checks(const struct iovec *iov,
unsigned long *nr_segs, size_t *count, int access_flags);
/* fs/block_dev.c */
-extern ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos);
extern ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos);
extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 02c1c9710be0..d0a79678f169 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -31,6 +31,7 @@ struct vm_area_struct;
#define ___GFP_THISNODE 0x40000u
#define ___GFP_RECLAIMABLE 0x80000u
#define ___GFP_NOTRACK 0x200000u
+#define ___GFP_NO_KSWAPD 0x400000u
#define ___GFP_OTHER_NODE 0x800000u
#define ___GFP_WRITE 0x1000000u
@@ -85,6 +86,7 @@ struct vm_area_struct;
#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */
#define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK) /* Don't track with kmemcheck */
+#define __GFP_NO_KSWAPD ((__force gfp_t)___GFP_NO_KSWAPD)
#define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
#define __GFP_WRITE ((__force gfp_t)___GFP_WRITE) /* Allocator intends to dirty page */
@@ -114,7 +116,8 @@ struct vm_area_struct;
__GFP_MOVABLE)
#define GFP_IOFS (__GFP_IO | __GFP_FS)
#define GFP_TRANSHUGE (GFP_HIGHUSER_MOVABLE | __GFP_COMP | \
- __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN)
+ __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \
+ __GFP_NO_KSWAPD)
#ifdef CONFIG_NUMA
#define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 2e31e8b3a190..bfe665621536 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -72,9 +72,9 @@ static inline int irq_to_gpio(unsigned int irq)
return -EINVAL;
}
-#endif
+#endif /* ! CONFIG_ARCH_HAVE_CUSTOM_GPIO_H */
-#else
+#else /* ! CONFIG_GENERIC_GPIO */
#include <linux/kernel.h>
#include <linux/types.h>
@@ -231,6 +231,21 @@ static inline int irq_to_gpio(unsigned irq)
return -EINVAL;
}
-#endif
+static inline int
+gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+ unsigned int gpio_offset, unsigned int pin_offset,
+ unsigned int npins)
+{
+ WARN_ON(1);
+ return -EINVAL;
+}
+
+static inline void
+gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+ WARN_ON(1);
+}
+
+#endif /* ! CONFIG_GENERIC_GPIO */
#endif /* __LINUX_GPIO_H */
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h
index 6ae9c631a1be..0464c85e63fd 100644
--- a/include/linux/hw_breakpoint.h
+++ b/include/linux/hw_breakpoint.h
@@ -1,35 +1,8 @@
#ifndef _LINUX_HW_BREAKPOINT_H
#define _LINUX_HW_BREAKPOINT_H
-enum {
- HW_BREAKPOINT_LEN_1 = 1,
- HW_BREAKPOINT_LEN_2 = 2,
- HW_BREAKPOINT_LEN_4 = 4,
- HW_BREAKPOINT_LEN_8 = 8,
-};
-
-enum {
- HW_BREAKPOINT_EMPTY = 0,
- HW_BREAKPOINT_R = 1,
- HW_BREAKPOINT_W = 2,
- HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W,
- HW_BREAKPOINT_X = 4,
- HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X,
-};
-
-enum bp_type_idx {
- TYPE_INST = 0,
-#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
- TYPE_DATA = 0,
-#else
- TYPE_DATA = 1,
-#endif
- TYPE_MAX
-};
-
-#ifdef __KERNEL__
-
#include <linux/perf_event.h>
+#include <uapi/linux/hw_breakpoint.h>
#ifdef CONFIG_HAVE_HW_BREAKPOINT
@@ -151,6 +124,4 @@ static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp)
}
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_HW_BREAKPOINT_H */
diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h
index df804ba73e0b..92a0dc75bc74 100644
--- a/include/linux/i2c-omap.h
+++ b/include/linux/i2c-omap.h
@@ -34,6 +34,7 @@ struct omap_i2c_bus_platform_data {
u32 clkrate;
u32 rev;
u32 flags;
+ void (*set_mpu_wkup_lat)(struct device *dev, long set);
};
#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index a123b13b70fd..7d8dfc7392f1 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -701,6 +701,13 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
#define COMPACTION_BUILD 0
#endif
+/* This helps us to avoid #ifdef CONFIG_SYMBOL_PREFIX */
+#ifdef CONFIG_SYMBOL_PREFIX
+#define SYMBOL_PREFIX CONFIG_SYMBOL_PREFIX
+#else
+#define SYMBOL_PREFIX ""
+#endif
+
/* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
# define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index e5ccb9ddd90e..dbd212723b74 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -82,16 +82,6 @@ static inline void mpol_cond_put(struct mempolicy *pol)
__mpol_put(pol);
}
-extern struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol);
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol)
-{
- if (!frompol)
- return frompol;
- return __mpol_cond_copy(tompol, frompol);
-}
-
extern struct mempolicy *__mpol_dup(struct mempolicy *pol);
static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
{
@@ -215,12 +205,6 @@ static inline void mpol_cond_put(struct mempolicy *pol)
{
}
-static inline struct mempolicy *mpol_cond_copy(struct mempolicy *to,
- struct mempolicy *from)
-{
- return from;
-}
-
static inline void mpol_get(struct mempolicy *pol)
{
}
diff --git a/include/linux/mfd/db8500-prcmu.h b/include/linux/mfd/db8500-prcmu.h
index b82f6ee66a0b..6ee4247df11e 100644
--- a/include/linux/mfd/db8500-prcmu.h
+++ b/include/linux/mfd/db8500-prcmu.h
@@ -515,7 +515,6 @@ enum romcode_read prcmu_get_rc_p2a(void);
enum ap_pwrst prcmu_get_xp70_current_state(void);
bool prcmu_has_arm_maxopp(void);
struct prcmu_fw_version *prcmu_get_fw_version(void);
-int prcmu_request_ape_opp_100_voltage(bool enable);
int prcmu_release_usb_wakeup_state(void);
void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
struct prcmu_auto_pm_config *idle);
@@ -564,6 +563,7 @@ int db8500_prcmu_set_arm_opp(u8 opp);
int db8500_prcmu_get_arm_opp(void);
int db8500_prcmu_set_ape_opp(u8 opp);
int db8500_prcmu_get_ape_opp(void);
+int db8500_prcmu_request_ape_opp_100_voltage(bool enable);
int db8500_prcmu_set_ddr_opp(u8 opp);
int db8500_prcmu_get_ddr_opp(void);
@@ -610,7 +610,7 @@ static inline int db8500_prcmu_get_ape_opp(void)
return APE_100_OPP;
}
-static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+static inline int db8500_prcmu_request_ape_opp_100_voltage(bool enable)
{
return 0;
}
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index c410d99bd667..c202d6c4d879 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -336,6 +336,11 @@ static inline int prcmu_get_ape_opp(void)
return db8500_prcmu_get_ape_opp();
}
+static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+ return db8500_prcmu_request_ape_opp_100_voltage(enable);
+}
+
static inline void prcmu_system_reset(u16 reset_code)
{
return db8500_prcmu_system_reset(reset_code);
@@ -507,6 +512,11 @@ static inline int prcmu_get_ape_opp(void)
return APE_100_OPP;
}
+static inline int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+ return 0;
+}
+
static inline int prcmu_set_arm_opp(u8 opp)
{
return 0;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index fa0680402738..bcaab4e6fe91 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1684,9 +1684,5 @@ 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 */
-extern void reset_zone_present_pages(void);
-extern void fixup_zone_present_pages(int nid, unsigned long start_pfn,
- unsigned long end_pfn);
-
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 943550dfe9ea..5c69315d60cc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -85,6 +85,7 @@ struct mmc_ext_csd {
bool boot_ro_lockable;
u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */
+ u8 raw_rpmb_size_mult; /* 168 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
@@ -206,6 +207,7 @@ struct mmc_part {
#define MMC_BLK_DATA_AREA_MAIN (1<<0)
#define MMC_BLK_DATA_AREA_BOOT (1<<1)
#define MMC_BLK_DATA_AREA_GP (1<<2)
+#define MMC_BLK_DATA_AREA_RPMB (1<<3)
};
/*
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 9b9cdafc7737..5bf7c2274fcb 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -170,6 +170,8 @@ extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+ bool is_rel_write);
extern int mmc_hw_reset(struct mmc_host *host);
extern int mmc_hw_reset_check(struct mmc_host *host);
extern int mmc_can_reset(struct mmc_card *card);
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 96531664a061..34be4f47293c 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -229,8 +229,9 @@ struct dw_mci_board {
u32 quirks; /* Workaround / Quirk flags */
unsigned int bus_hz; /* Clock speed at the cclk_in pad */
- unsigned int caps; /* Capabilities */
- unsigned int caps2; /* More capabilities */
+ u32 caps; /* Capabilities */
+ u32 caps2; /* More capabilities */
+ u32 pm_caps; /* PM capabilities */
/*
* Override fifo depth. If 0, autodetect it from the FIFOTH register,
* but note that this may not be reliable after a bootloader has used
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 7abb0e1f7bda..61a10c17aabd 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -53,12 +53,12 @@ struct mmc_ios {
#define MMC_TIMING_LEGACY 0
#define MMC_TIMING_MMC_HS 1
#define MMC_TIMING_SD_HS 2
-#define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
-#define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
-#define MMC_TIMING_UHS_SDR50 3
-#define MMC_TIMING_UHS_SDR104 4
-#define MMC_TIMING_UHS_DDR50 5
-#define MMC_TIMING_MMC_HS200 6
+#define MMC_TIMING_UHS_SDR12 3
+#define MMC_TIMING_UHS_SDR25 4
+#define MMC_TIMING_UHS_SDR50 5
+#define MMC_TIMING_UHS_SDR104 6
+#define MMC_TIMING_UHS_DDR50 7
+#define MMC_TIMING_MMC_HS200 8
#define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1
@@ -136,6 +136,7 @@ struct mmc_host_ops {
void (*enable_preset_value)(struct mmc_host *host, bool enable);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
+ void (*card_event)(struct mmc_host *host);
};
struct mmc_card;
@@ -211,7 +212,7 @@ struct mmc_host {
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
- unsigned long caps; /* Host capabilities */
+ u32 caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
#define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
@@ -241,7 +242,7 @@ struct mmc_host {
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
- unsigned int caps2; /* More host capabilities */
+ u32 caps2; /* More host capabilities */
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 01e4b394029b..94d532e41c61 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -286,6 +286,7 @@ struct _mmc_csd {
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
+#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
@@ -339,6 +340,7 @@ struct _mmc_csd {
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
diff --git a/include/linux/mmc/mxs-mmc.h b/include/linux/mmc/mxs-mmc.h
deleted file mode 100644
index 7c2ad3a7f2f3..000000000000
--- a/include/linux/mmc/mxs-mmc.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __LINUX_MMC_MXS_MMC_H__
-#define __LINUX_MMC_MXS_MMC_H__
-
-struct mxs_mmc_platform_data {
- int wp_gpio; /* write protect pin */
- unsigned int flags;
-#define SLOTF_4_BIT_CAPABLE (1 << 0)
-#define SLOTF_8_BIT_CAPABLE (1 << 1)
-};
-
-#endif /* __LINUX_MMC_MXS_MMC_H__ */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index 1edcb4dad8c4..4bbc3301fbbf 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -92,6 +92,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0)
#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1)
+/* The system physically doesn't support 1.8v, even if the host does */
+#define SDHCI_QUIRK2_NO_1_8_V (1<<2)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -158,8 +160,8 @@ struct sdhci_host {
struct timer_list timer; /* Timer for timeouts */
- unsigned int caps; /* Alternative CAPABILITY_0 */
- unsigned int caps1; /* Alternative CAPABILITY_1 */
+ u32 caps; /* Alternative CAPABILITY_0 */
+ u32 caps1; /* Alternative CAPABILITY_1 */
unsigned int ocr_avail_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd;
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 50aaca81f63d..a23923ba8263 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -752,7 +752,7 @@ extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
unsigned long size,
enum memmap_context context);
-extern void lruvec_init(struct lruvec *lruvec, struct zone *zone);
+extern void lruvec_init(struct lruvec *lruvec);
static inline struct zone *lruvec_zone(struct lruvec *lruvec)
{
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f8eda0276f03..a848ffc327f4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1488,6 +1488,9 @@ struct napi_gro_cb {
/* Used in ipv6_gro_receive() */
int proto;
+
+ /* used in skb_gro_receive() slow path */
+ struct sk_buff *last;
};
#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb)
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index e20e3af68fb6..0506eb53519b 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -42,10 +42,12 @@ static inline struct device_node *of_find_matching_node_by_address(
{
return NULL;
}
+#ifndef of_iomap
static inline void __iomem *of_iomap(struct device_node *device, int index)
{
return NULL;
}
+#endif
static inline const __be32 *of_get_address(struct device_node *dev, int index,
u64 *size, unsigned int *flags)
{
diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h
index 250a4acddb2b..bd1e86071e57 100644
--- a/include/linux/percpu-rwsem.h
+++ b/include/linux/percpu-rwsem.h
@@ -13,7 +13,7 @@ struct percpu_rw_semaphore {
};
#define light_mb() barrier()
-#define heavy_mb() synchronize_sched()
+#define heavy_mb() synchronize_sched_expedited()
static inline void percpu_down_read(struct percpu_rw_semaphore *p)
{
@@ -51,7 +51,7 @@ static inline void percpu_down_write(struct percpu_rw_semaphore *p)
{
mutex_lock(&p->mtx);
p->locked = true;
- synchronize_sched(); /* make sure that all readers exit the rcu_read_lock_sched region */
+ synchronize_sched_expedited(); /* make sure that all readers exit the rcu_read_lock_sched region */
while (__percpu_count(p->counters))
msleep(1);
heavy_mb(); /* C, between read of p->counter and write to data, paired with B */
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index 4f0abb9f1c09..47a1bdd88878 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -46,11 +46,11 @@
* @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
* (open emitter). Sending this config will enabale open drain mode, the
* argument is ignored.
+ * @PIN_CONFIG_INPUT_SCHMITT_DISABLE: disable schmitt-trigger mode on the pin.
* @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
* schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
* the threshold value is given on a custom format as argument when
- * setting pins to this mode. The argument zero turns the schmitt trigger
- * off.
+ * setting pins to this mode.
* @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
* which means it will wait for signals to settle when reading inputs. The
* argument gives the debounce time on a custom format. Setting the
@@ -74,6 +74,7 @@ enum pin_config_param {
PIN_CONFIG_DRIVE_PUSH_PULL,
PIN_CONFIG_DRIVE_OPEN_DRAIN,
PIN_CONFIG_DRIVE_OPEN_SOURCE,
+ PIN_CONFIG_INPUT_SCHMITT_DISABLE,
PIN_CONFIG_INPUT_SCHMITT,
PIN_CONFIG_INPUT_DEBOUNCE,
PIN_CONFIG_POWER_SOURCE,
diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h
index 7d087f03e91e..04d6700d99af 100644
--- a/include/linux/pinctrl/pinctrl.h
+++ b/include/linux/pinctrl/pinctrl.h
@@ -134,6 +134,25 @@ extern void pinctrl_add_gpio_range(struct pinctrl_dev *pctldev,
extern void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *ranges,
unsigned nranges);
+extern void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range);
+
+extern struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
+ struct pinctrl_gpio_range *range);
+extern struct pinctrl_gpio_range *
+pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
+ unsigned int pin);
+
+#ifdef CONFIG_OF
+extern struct pinctrl_dev *of_pinctrl_get(struct device_node *np);
+#else
+static inline
+struct pinctrl_dev *of_pinctrl_get(struct device_node *np)
+{
+ return NULL;
+}
+#endif /* CONFIG_OF */
+
extern const char *pinctrl_dev_get_name(struct pinctrl_dev *pctldev);
extern void *pinctrl_dev_get_drvdata(struct pinctrl_dev *pctldev);
#else
diff --git a/include/linux/platform_data/ads7828.h b/include/linux/platform_data/ads7828.h
new file mode 100644
index 000000000000..3245f45f9d77
--- /dev/null
+++ b/include/linux/platform_data/ads7828.h
@@ -0,0 +1,29 @@
+/*
+ * TI ADS7828 A/D Converter platform data definition
+ *
+ * Copyright (c) 2012 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * For further information, see the Documentation/hwmon/ads7828 file.
+ *
+ * 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 _PDATA_ADS7828_H
+#define _PDATA_ADS7828_H
+
+/**
+ * struct ads7828_platform_data - optional ADS7828 connectivity info
+ * @diff_input: Differential input mode.
+ * @ext_vref: Use an external voltage reference.
+ * @vref_mv: Voltage reference value, if external.
+ */
+struct ads7828_platform_data {
+ bool diff_input;
+ bool ext_vref;
+ unsigned int vref_mv;
+};
+
+#endif /* _PDATA_ADS7828_H */
diff --git a/include/linux/platform_data/clk-integrator.h b/include/linux/platform_data/clk-integrator.h
index 83fe9c283bb8..280edac9d0a5 100644
--- a/include/linux/platform_data/clk-integrator.h
+++ b/include/linux/platform_data/clk-integrator.h
@@ -1 +1,3 @@
void integrator_clk_init(bool is_cp);
+void integrator_impd1_clk_init(void __iomem *base, unsigned int id);
+void integrator_impd1_clk_exit(unsigned int id);
diff --git a/include/linux/platform_data/omap_ocp2scp.h b/include/linux/platform_data/omap_ocp2scp.h
new file mode 100644
index 000000000000..5c6c3939355f
--- /dev/null
+++ b/include/linux/platform_data/omap_ocp2scp.h
@@ -0,0 +1,31 @@
+/*
+ * omap_ocp2scp.h -- ocp2scp header file
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 __DRIVERS_OMAP_OCP2SCP_H
+#define __DRIVERS_OMAP_OCP2SCP_H
+
+struct omap_ocp2scp_dev {
+ const char *drv_name;
+ struct resource *res;
+};
+
+struct omap_ocp2scp_platform_data {
+ int dev_cnt;
+ struct omap_ocp2scp_dev **devices;
+};
+#endif /* __DRIVERS_OMAP_OCP2SCP_H */
diff --git a/include/linux/platform_data/pinctrl-coh901.h b/include/linux/platform_data/pinctrl-coh901.h
index 30dea251b835..dfbc65d10484 100644
--- a/include/linux/platform_data/pinctrl-coh901.h
+++ b/include/linux/platform_data/pinctrl-coh901.h
@@ -13,14 +13,10 @@
* struct u300_gpio_platform - U300 GPIO platform data
* @ports: number of GPIO block ports
* @gpio_base: first GPIO number for this block (use a free range)
- * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
- * @pinctrl_device: pin control device to spawn as child
*/
struct u300_gpio_platform {
u8 ports;
int gpio_base;
- int gpio_irq_base;
- struct platform_device *pinctrl_device;
};
#endif /* __MACH_U300_GPIO_U300_H */
diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/include/linux/platform_data/pinctrl-nomadik.h
index 3b8ec60af351..f73b2f0c55b7 100644
--- a/arch/arm/plat-nomadik/include/plat/pincfg.h
+++ b/include/linux/platform_data/pinctrl-nomadik.h
@@ -1,16 +1,17 @@
/*
- * Copyright (C) ST-Ericsson SA 2010
+ * Structures and registers for GPIO access in the Nomadik SoC
*
- * License terms: GNU General Public License, version 2
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Copyright (C) 2008 STMicroelectronics
+ * Author: Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
*
- * Based on arch/arm/mach-pxa/include/mach/mfp.h:
- * Copyright (C) 2007 Marvell International Ltd.
- * eric miao <eric.miao@marvell.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 __PLAT_PINCFG_H
-#define __PLAT_PINCFG_H
+#ifndef __PLAT_NOMADIK_GPIO
+#define __PLAT_NOMADIK_GPIO
/*
* pin configurations are represented by 32-bit integers:
@@ -166,8 +167,100 @@ typedef unsigned long pin_cfg_t;
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val))
+/*
+ * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving
+ * the "gpio" namespace for generic and cross-machine functions
+ */
+
+#define GPIO_BLOCK_SHIFT 5
+#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT)
+
+/* Register in the logic block */
+#define NMK_GPIO_DAT 0x00
+#define NMK_GPIO_DATS 0x04
+#define NMK_GPIO_DATC 0x08
+#define NMK_GPIO_PDIS 0x0c
+#define NMK_GPIO_DIR 0x10
+#define NMK_GPIO_DIRS 0x14
+#define NMK_GPIO_DIRC 0x18
+#define NMK_GPIO_SLPC 0x1c
+#define NMK_GPIO_AFSLA 0x20
+#define NMK_GPIO_AFSLB 0x24
+#define NMK_GPIO_LOWEMI 0x28
+
+#define NMK_GPIO_RIMSC 0x40
+#define NMK_GPIO_FIMSC 0x44
+#define NMK_GPIO_IS 0x48
+#define NMK_GPIO_IC 0x4c
+#define NMK_GPIO_RWIMSC 0x50
+#define NMK_GPIO_FWIMSC 0x54
+#define NMK_GPIO_WKS 0x58
+/* These appear in DB8540 and later ASICs */
+#define NMK_GPIO_EDGELEVEL 0x5C
+#define NMK_GPIO_LEVEL 0x60
+
+/* Alternate functions: function C is set in hw by setting both A and B */
+#define NMK_GPIO_ALT_GPIO 0
+#define NMK_GPIO_ALT_A 1
+#define NMK_GPIO_ALT_B 2
+#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B)
+
+#define NMK_GPIO_ALT_CX_SHIFT 2
+#define NMK_GPIO_ALT_C1 ((1<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
+#define NMK_GPIO_ALT_C2 ((2<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
+#define NMK_GPIO_ALT_C3 ((3<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
+#define NMK_GPIO_ALT_C4 ((4<<NMK_GPIO_ALT_CX_SHIFT) | NMK_GPIO_ALT_C)
+
+/* Pull up/down values */
+enum nmk_gpio_pull {
+ NMK_GPIO_PULL_NONE,
+ NMK_GPIO_PULL_UP,
+ NMK_GPIO_PULL_DOWN,
+};
+
+/* Sleep mode */
+enum nmk_gpio_slpm {
+ NMK_GPIO_SLPM_INPUT,
+ NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
+ NMK_GPIO_SLPM_NOCHANGE,
+ NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
+};
+
+/* Older deprecated pin config API that should go away soon */
extern int nmk_config_pin(pin_cfg_t cfg, bool sleep);
extern int nmk_config_pins(pin_cfg_t *cfgs, int num);
extern int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num);
-
+extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
+extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
+#ifdef CONFIG_PINCTRL_NOMADIK
+extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
+#else
+static inline int nmk_gpio_set_mode(int gpio, int gpio_mode)
+{
+ return -ENODEV;
+}
#endif
+extern int nmk_gpio_get_mode(int gpio);
+
+extern void nmk_gpio_wakeups_suspend(void);
+extern void nmk_gpio_wakeups_resume(void);
+
+extern void nmk_gpio_clocks_enable(void);
+extern void nmk_gpio_clocks_disable(void);
+
+extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
+
+/*
+ * Platform data to register a block: only the initial gpio/irq number.
+ */
+struct nmk_gpio_platform_data {
+ char *name;
+ int first_gpio;
+ int first_irq;
+ int num_gpio;
+ u32 (*get_secondary_status)(unsigned int bank);
+ void (*set_ioforce)(bool enable);
+ bool supports_sleepmode;
+};
+
+#endif /* __PLAT_NOMADIK_GPIO */
diff --git a/include/linux/platform_data/pxa_sdhci.h b/include/linux/platform_data/pxa_sdhci.h
index 59acd987ed34..27d3156d093a 100644
--- a/include/linux/platform_data/pxa_sdhci.h
+++ b/include/linux/platform_data/pxa_sdhci.h
@@ -38,6 +38,7 @@
* @max_speed: the maximum speed supported
* @host_caps: Standard MMC host capabilities bit field.
* @quirks: quirks of platfrom
+ * @quirks2: quirks2 of platfrom
* @pm_caps: pm_caps of platfrom
*/
struct sdhci_pxa_platdata {
@@ -48,9 +49,10 @@ struct sdhci_pxa_platdata {
unsigned int ext_cd_gpio;
bool ext_cd_gpio_invert;
unsigned int max_speed;
- unsigned int host_caps;
- unsigned int host_caps2;
+ u32 host_caps;
+ u32 host_caps2;
unsigned int quirks;
+ unsigned int quirks2;
unsigned int pm_caps;
};
diff --git a/include/linux/rio.h b/include/linux/rio.h
index 4187da511006..a3e784278667 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -275,9 +275,11 @@ struct rio_id_table {
* struct rio_net - RIO network info
* @node: Node in global list of RIO networks
* @devices: List of devices in this network
+ * @switches: List of switches in this netowrk
* @mports: List of master ports accessing this network
* @hport: Default port for accessing this network
* @id: RIO network ID
+ * @destid_table: destID allocation table
*/
struct rio_net {
struct list_head node; /* node in list of networks */
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index c64de9dd7631..2f694f3846a9 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -46,8 +46,9 @@ struct ads7846_platform_data {
u16 debounce_rep; /* additional consecutive good readings
* required after the first two */
int gpio_pendown; /* the GPIO used to decide the pendown
- * state if get_pendown_state == NULL
- */
+ * state if get_pendown_state == NULL */
+ int gpio_pendown_debounce; /* platform specific debounce time for
+ * the gpio_pendown */
int (*get_pendown_state)(void);
int (*filter_init) (const struct ads7846_platform_data *pdata,
void **filter_data);
diff --git a/include/media/adv7604.h b/include/media/adv7604.h
index 171b957db743..dc004bc926c9 100644
--- a/include/media/adv7604.h
+++ b/include/media/adv7604.h
@@ -40,14 +40,6 @@ enum adv7604_op_ch_sel {
ADV7604_OP_CH_SEL_RBG = 5,
};
-/* Primary mode (IO register 0x01, [3:0]) */
-enum adv7604_prim_mode {
- ADV7604_PRIM_MODE_COMP = 1,
- ADV7604_PRIM_MODE_RGB = 2,
- ADV7604_PRIM_MODE_HDMI_COMP = 5,
- ADV7604_PRIM_MODE_HDMI_GR = 6,
-};
-
/* Input Color Space (IO register 0x02, [7:4]) */
enum adv7604_inp_color_space {
ADV7604_INP_COLOR_SPACE_LIM_RGB = 0,
@@ -103,9 +95,6 @@ struct adv7604_platform_data {
/* Bus rotation and reordering */
enum adv7604_op_ch_sel op_ch_sel;
- /* Primary mode */
- enum adv7604_prim_mode prim_mode;
-
/* Select output format */
enum adv7604_op_format_sel op_format_sel;
@@ -142,6 +131,16 @@ struct adv7604_platform_data {
u8 i2c_vdp;
};
+/*
+ * Mode of operation.
+ * This is used as the input argument of the s_routing video op.
+ */
+enum adv7604_mode {
+ ADV7604_MODE_COMP,
+ ADV7604_MODE_GR,
+ ADV7604_MODE_HDMI,
+};
+
#define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE (V4L2_CID_DV_CLASS_BASE + 0x1000)
#define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL (V4L2_CID_DV_CLASS_BASE + 0x1001)
#define V4L2_CID_ADV_RX_FREE_RUN_COLOR (V4L2_CID_DV_CLASS_BASE + 0x1002)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 6feeccd83dd7..4af45e33105d 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -525,6 +525,7 @@ static inline __u32 cookie_v6_init_sequence(struct sock *sk,
extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss,
int nonagle);
extern bool tcp_may_send_now(struct sock *sk);
+extern int __tcp_retransmit_skb(struct sock *, struct sk_buff *);
extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
extern void tcp_retransmit_timer(struct sock *sk);
extern void tcp_xmit_retransmit_queue(struct sock *);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 6f0ba01afe73..63445ede48bb 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1351,7 +1351,7 @@ struct xfrm6_tunnel {
};
extern void xfrm_init(void);
-extern void xfrm4_init(int rt_hash_size);
+extern void xfrm4_init(void);
extern int xfrm_state_init(struct net *net);
extern void xfrm_state_fini(struct net *net);
extern void xfrm4_state_init(void);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 88fae8d20154..55367b04dc94 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -135,6 +135,8 @@ struct scsi_device {
* because we did a bus reset. */
unsigned use_10_for_rw:1; /* first try 10-byte read / write */
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
+ unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */
+ unsigned no_write_same:1; /* no WRITE SAME command */
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
unsigned skip_vpd_pages:1; /* do not read VPD pages */
@@ -362,6 +364,8 @@ extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout,
int retries, struct scsi_sense_hdr *sshdr);
extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf,
int buf_len);
+extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer,
+ unsigned int len, unsigned char opcode);
extern int scsi_device_set_state(struct scsi_device *sdev,
enum scsi_device_state state);
extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type,
diff --git a/include/trace/events/gfpflags.h b/include/trace/events/gfpflags.h
index 9391706e9254..d6fd8e5b14b7 100644
--- a/include/trace/events/gfpflags.h
+++ b/include/trace/events/gfpflags.h
@@ -36,6 +36,7 @@
{(unsigned long)__GFP_RECLAIMABLE, "GFP_RECLAIMABLE"}, \
{(unsigned long)__GFP_MOVABLE, "GFP_MOVABLE"}, \
{(unsigned long)__GFP_NOTRACK, "GFP_NOTRACK"}, \
+ {(unsigned long)__GFP_NO_KSWAPD, "GFP_NO_KSWAPD"}, \
{(unsigned long)__GFP_OTHER_NODE, "GFP_OTHER_NODE"} \
) : "GFP_NOWAIT"
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index e194387ef784..19e765fbfef7 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -415,3 +415,4 @@ header-y += wireless.h
header-y += x25.h
header-y += xattr.h
header-y += xfrm.h
+header-y += hw_breakpoint.h
diff --git a/include/uapi/linux/hw_breakpoint.h b/include/uapi/linux/hw_breakpoint.h
new file mode 100644
index 000000000000..b04000a2296a
--- /dev/null
+++ b/include/uapi/linux/hw_breakpoint.h
@@ -0,0 +1,30 @@
+#ifndef _UAPI_LINUX_HW_BREAKPOINT_H
+#define _UAPI_LINUX_HW_BREAKPOINT_H
+
+enum {
+ HW_BREAKPOINT_LEN_1 = 1,
+ HW_BREAKPOINT_LEN_2 = 2,
+ HW_BREAKPOINT_LEN_4 = 4,
+ HW_BREAKPOINT_LEN_8 = 8,
+};
+
+enum {
+ HW_BREAKPOINT_EMPTY = 0,
+ HW_BREAKPOINT_R = 1,
+ HW_BREAKPOINT_W = 2,
+ HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W,
+ HW_BREAKPOINT_X = 4,
+ HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X,
+};
+
+enum bp_type_idx {
+ TYPE_INST = 0,
+#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS
+ TYPE_DATA = 0,
+#else
+ TYPE_DATA = 1,
+#endif
+ TYPE_MAX
+};
+
+#endif /* _UAPI_LINUX_HW_BREAKPOINT_H */
diff --git a/include/uapi/linux/oom.h b/include/uapi/linux/oom.h
index a49c4afc7060..b29272d621ce 100644
--- a/include/uapi/linux/oom.h
+++ b/include/uapi/linux/oom.h
@@ -8,4 +8,13 @@
#define OOM_SCORE_ADJ_MIN (-1000)
#define OOM_SCORE_ADJ_MAX 1000
+/*
+ * /proc/<pid>/oom_adj set to -17 protects from the oom killer for legacy
+ * purposes.
+ */
+#define OOM_DISABLE (-17)
+/* inclusive */
+#define OOM_ADJUST_MIN (-16)
+#define OOM_ADJUST_MAX 15
+
#endif /* _UAPI__INCLUDE_LINUX_OOM_H */
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index 9a7b487c6fe2..fe8a916507ed 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -111,14 +111,16 @@ static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type)
* Count the number of breakpoints of the same type and same task.
* The given event must be not on the list.
*/
-static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type)
+static int task_bp_pinned(int cpu, struct perf_event *bp, enum bp_type_idx type)
{
struct task_struct *tsk = bp->hw.bp_target;
struct perf_event *iter;
int count = 0;
list_for_each_entry(iter, &bp_task_head, hw.bp_list) {
- if (iter->hw.bp_target == tsk && find_slot_idx(iter) == type)
+ if (iter->hw.bp_target == tsk &&
+ find_slot_idx(iter) == type &&
+ cpu == iter->cpu)
count += hw_breakpoint_weight(iter);
}
@@ -141,7 +143,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
if (!tsk)
slots->pinned += max_task_bp_pinned(cpu, type);
else
- slots->pinned += task_bp_pinned(bp, type);
+ slots->pinned += task_bp_pinned(cpu, bp, type);
slots->flexible = per_cpu(nr_bp_flexible[type], cpu);
return;
@@ -154,7 +156,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
if (!tsk)
nr += max_task_bp_pinned(cpu, type);
else
- nr += task_bp_pinned(bp, type);
+ nr += task_bp_pinned(cpu, bp, type);
if (nr > slots->pinned)
slots->pinned = nr;
@@ -188,7 +190,7 @@ static void toggle_bp_task_slot(struct perf_event *bp, int cpu, bool enable,
int old_idx = 0;
int idx = 0;
- old_count = task_bp_pinned(bp, type);
+ old_count = task_bp_pinned(cpu, bp, type);
old_idx = old_count - 1;
idx = old_idx + weight;
diff --git a/kernel/futex.c b/kernel/futex.c
index 3717e7b306e0..19eb089ca003 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -716,7 +716,7 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
struct futex_pi_state **ps,
struct task_struct *task, int set_waiters)
{
- int lock_taken, ret, ownerdied = 0;
+ int lock_taken, ret, force_take = 0;
u32 uval, newval, curval, vpid = task_pid_vnr(task);
retry:
@@ -755,17 +755,15 @@ retry:
newval = curval | FUTEX_WAITERS;
/*
- * There are two cases, where a futex might have no owner (the
- * owner TID is 0): OWNER_DIED. We take over the futex in this
- * case. We also do an unconditional take over, when the owner
- * of the futex died.
- *
- * This is safe as we are protected by the hash bucket lock !
+ * Should we force take the futex? See below.
*/
- if (unlikely(ownerdied || !(curval & FUTEX_TID_MASK))) {
- /* Keep the OWNER_DIED bit */
+ if (unlikely(force_take)) {
+ /*
+ * Keep the OWNER_DIED and the WAITERS bit and set the
+ * new TID value.
+ */
newval = (curval & ~FUTEX_TID_MASK) | vpid;
- ownerdied = 0;
+ force_take = 0;
lock_taken = 1;
}
@@ -775,7 +773,7 @@ retry:
goto retry;
/*
- * We took the lock due to owner died take over.
+ * We took the lock due to forced take over.
*/
if (unlikely(lock_taken))
return 1;
@@ -790,20 +788,25 @@ retry:
switch (ret) {
case -ESRCH:
/*
- * No owner found for this futex. Check if the
- * OWNER_DIED bit is set to figure out whether
- * this is a robust futex or not.
+ * We failed to find an owner for this
+ * futex. So we have no pi_state to block
+ * on. This can happen in two cases:
+ *
+ * 1) The owner died
+ * 2) A stale FUTEX_WAITERS bit
+ *
+ * Re-read the futex value.
*/
if (get_futex_value_locked(&curval, uaddr))
return -EFAULT;
/*
- * We simply start over in case of a robust
- * futex. The code above will take the futex
- * and return happy.
+ * If the owner died or we have a stale
+ * WAITERS bit the owner TID in the user space
+ * futex is 0.
*/
- if (curval & FUTEX_OWNER_DIED) {
- ownerdied = 1;
+ if (!(curval & FUTEX_TID_MASK)) {
+ force_take = 1;
goto retry;
}
default:
@@ -840,6 +843,9 @@ static void wake_futex(struct futex_q *q)
{
struct task_struct *p = q->task;
+ if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n"))
+ return;
+
/*
* We set q->lock_ptr = NULL _before_ we wake up the task. If
* a non-futex wake up happens on another CPU then the task
@@ -1075,6 +1081,10 @@ retry_private:
plist_for_each_entry_safe(this, next, head, list) {
if (match_futex (&this->key, &key1)) {
+ if (this->pi_state || this->rt_waiter) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
wake_futex(this);
if (++ret >= nr_wake)
break;
@@ -1087,6 +1097,10 @@ retry_private:
op_ret = 0;
plist_for_each_entry_safe(this, next, head, list) {
if (match_futex (&this->key, &key2)) {
+ if (this->pi_state || this->rt_waiter) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
wake_futex(this);
if (++op_ret >= nr_wake2)
break;
@@ -1095,6 +1109,7 @@ retry_private:
ret += op_ret;
}
+out_unlock:
double_unlock_hb(hb1, hb2);
out_put_keys:
put_futex_key(&key2);
@@ -1384,9 +1399,13 @@ retry_private:
/*
* FUTEX_WAIT_REQEUE_PI and FUTEX_CMP_REQUEUE_PI should always
* be paired with each other and no other futex ops.
+ *
+ * We should never be requeueing a futex_q with a pi_state,
+ * which is awaiting a futex_unlock_pi().
*/
if ((requeue_pi && !this->rt_waiter) ||
- (!requeue_pi && this->rt_waiter)) {
+ (!requeue_pi && this->rt_waiter) ||
+ this->pi_state) {
ret = -EINVAL;
break;
}
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 4e69e24d3d7d..96f3a1d9c379 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -177,8 +177,8 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
irq_base = irq_alloc_descs(first_irq, first_irq, size,
of_node_to_nid(of_node));
if (irq_base < 0) {
- WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
- first_irq);
+ pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
+ first_irq);
irq_base = first_irq;
}
} else
diff --git a/kernel/modsign_pubkey.c b/kernel/modsign_pubkey.c
index 4646eb2c3820..767e559dfb10 100644
--- a/kernel/modsign_pubkey.c
+++ b/kernel/modsign_pubkey.c
@@ -21,10 +21,10 @@ struct key *modsign_keyring;
extern __initdata const u8 modsign_certificate_list[];
extern __initdata const u8 modsign_certificate_list_end[];
asm(".section .init.data,\"aw\"\n"
- "modsign_certificate_list:\n"
+ SYMBOL_PREFIX "modsign_certificate_list:\n"
".incbin \"signing_key.x509\"\n"
".incbin \"extra_certificates\"\n"
- "modsign_certificate_list_end:"
+ SYMBOL_PREFIX "modsign_certificate_list_end:"
);
/*
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index ea1b1df5dbb0..f2970bddc5ea 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -27,13 +27,13 @@
* - Information block
*/
struct module_signature {
- enum pkey_algo algo : 8; /* Public-key crypto algorithm */
- enum pkey_hash_algo hash : 8; /* Digest algorithm */
- enum pkey_id_type id_type : 8; /* Key identifier type */
- u8 signer_len; /* Length of signer's name */
- u8 key_id_len; /* Length of key identifier */
- u8 __pad[3];
- __be32 sig_len; /* Length of signature data */
+ u8 algo; /* Public-key crypto algorithm [enum pkey_algo] */
+ u8 hash; /* Digest algorithm [enum pkey_hash_algo] */
+ u8 id_type; /* Key identifier type [enum pkey_id_type] */
+ u8 signer_len; /* Length of signer's name */
+ u8 key_id_len; /* Length of key identifier */
+ u8 __pad[3];
+ __be32 sig_len; /* Length of signature data */
};
/*
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c
index 0984a21076a3..15f60d01198b 100644
--- a/kernel/sched/auto_group.c
+++ b/kernel/sched/auto_group.c
@@ -143,15 +143,11 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag)
p->signal->autogroup = autogroup_kref_get(ag);
- if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled))
- goto out;
-
t = p;
do {
sched_move_task(t);
} while_each_thread(p, t);
-out:
unlock_task_sighand(p, &flags);
autogroup_kref_put(prev);
}
diff --git a/kernel/sched/auto_group.h b/kernel/sched/auto_group.h
index 8bd047142816..443232ebbb53 100644
--- a/kernel/sched/auto_group.h
+++ b/kernel/sched/auto_group.h
@@ -4,11 +4,6 @@
#include <linux/rwsem.h>
struct autogroup {
- /*
- * reference doesn't mean how many thread attach to this
- * autogroup now. It just stands for the number of task
- * could use this autogroup.
- */
struct kref kref;
struct task_group *tg;
struct rw_semaphore lock;
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 9d4c8d5a1f53..c8c21be11ab4 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -116,7 +116,7 @@ static unsigned long get_timestamp(int this_cpu)
return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */
}
-static unsigned long get_sample_period(void)
+static u64 get_sample_period(void)
{
/*
* convert watchdog_thresh from seconds to ns
@@ -125,7 +125,7 @@ static unsigned long get_sample_period(void)
* and hard thresholds) to increment before the
* hardlockup detector generates a warning
*/
- return get_softlockup_thresh() * (NSEC_PER_SEC / 5);
+ return get_softlockup_thresh() * ((u64)NSEC_PER_SEC / 5);
}
/* Commands for resetting the watchdog */
@@ -368,6 +368,9 @@ static void watchdog_disable(unsigned int cpu)
{
struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
+ if (!watchdog_enabled)
+ return;
+
watchdog_set_prio(SCHED_NORMAL, 0);
hrtimer_cancel(hrtimer);
/* disable the perf event */
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 042d221d33cc..1dae900df798 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1361,8 +1361,19 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,
WARN_ON_ONCE(timer->function != delayed_work_timer_fn ||
timer->data != (unsigned long)dwork);
- BUG_ON(timer_pending(timer));
- BUG_ON(!list_empty(&work->entry));
+ WARN_ON_ONCE(timer_pending(timer));
+ WARN_ON_ONCE(!list_empty(&work->entry));
+
+ /*
+ * If @delay is 0, queue @dwork->work immediately. This is for
+ * both optimization and correctness. The earliest @timer can
+ * expire is on the closest next tick and delayed_work users depend
+ * on that there's no such delay when @delay is 0.
+ */
+ if (!delay) {
+ __queue_work(cpu, wq, &dwork->work);
+ return;
+ }
timer_stats_timer_set_start_info(&dwork->timer);
@@ -1417,9 +1428,6 @@ bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
bool ret = false;
unsigned long flags;
- if (!delay)
- return queue_work_on(cpu, wq, &dwork->work);
-
/* read the comment in __queue_work() */
local_irq_save(flags);
@@ -2407,8 +2415,10 @@ static int rescuer_thread(void *__wq)
repeat:
set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop())
+ if (kthread_should_stop()) {
+ __set_current_state(TASK_RUNNING);
return 0;
+ }
/*
* See whether any cpu is asking for help. Unbounded
diff --git a/lib/Makefile b/lib/Makefile
index 821a16229111..a08b791200f3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -163,7 +163,7 @@ $(obj)/crc32table.h: $(obj)/gen_crc32table
#
obj-$(CONFIG_OID_REGISTRY) += oid_registry.o
-$(obj)/oid_registry.c: $(obj)/oid_registry_data.c
+$(obj)/oid_registry.o: $(obj)/oid_registry_data.c
$(obj)/oid_registry_data.c: $(srctree)/include/linux/oid_registry.h \
$(src)/build_OID_registry
diff --git a/lib/asn1_decoder.c b/lib/asn1_decoder.c
index de2c8b5a715b..5293d2433029 100644
--- a/lib/asn1_decoder.c
+++ b/lib/asn1_decoder.c
@@ -91,7 +91,7 @@ next_tag:
/* Extract the length */
len = data[dp++];
- if (len < 0x7f) {
+ if (len <= 0x7f) {
dp += len;
goto next_tag;
}
diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h
index 678ce4f1e124..095ab157a521 100644
--- a/lib/mpi/longlong.h
+++ b/lib/mpi/longlong.h
@@ -641,7 +641,14 @@ do { \
************** MIPS *****************
***************************************/
#if defined(__mips__) && W_TYPE_SIZE == 32
-#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7
+#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
+#define umul_ppmm(w1, w0, u, v) \
+do { \
+ UDItype __ll = (UDItype)(u) * (v); \
+ w1 = __ll >> 32; \
+ w0 = __ll; \
+} while (0)
+#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("multu %2,%3" \
: "=l" ((USItype)(w0)), \
@@ -666,7 +673,15 @@ do { \
************** MIPS/64 **************
***************************************/
#if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64
-#if __GNUC__ > 2 || __GNUC_MINOR__ >= 7
+#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 4
+#define umul_ppmm(w1, w0, u, v) \
+do { \
+ typedef unsigned int __ll_UTItype __attribute__((mode(TI))); \
+ __ll_UTItype __ll = (__ll_UTItype)(u) * (v); \
+ w1 = __ll >> 64; \
+ w0 = __ll; \
+} while (0)
+#elif __GNUC__ > 2 || __GNUC_MINOR__ >= 7
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("dmultu %2,%3" \
: "=l" ((UDItype)(w0)), \
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 434be4ae7a04..f468185b3b28 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -198,8 +198,6 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
int order = ilog2(BITS_PER_LONG);
__free_pages_bootmem(pfn_to_page(start), order);
- fixup_zone_present_pages(page_to_nid(pfn_to_page(start)),
- start, start + BITS_PER_LONG);
count += BITS_PER_LONG;
start += BITS_PER_LONG;
} else {
@@ -210,9 +208,6 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
if (vec & 1) {
page = pfn_to_page(start + off);
__free_pages_bootmem(page, 0);
- fixup_zone_present_pages(
- page_to_nid(page),
- start + off, start + off + 1);
count++;
}
vec >>= 1;
@@ -226,11 +221,8 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata)
pages = bdata->node_low_pfn - bdata->node_min_pfn;
pages = bootmem_bootmap_pages(pages);
count += pages;
- while (pages--) {
- fixup_zone_present_pages(page_to_nid(page),
- page_to_pfn(page), page_to_pfn(page) + 1);
+ while (pages--)
__free_pages_bootmem(page++, 0);
- }
bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count);
diff --git a/mm/compaction.c b/mm/compaction.c
index 9eef55838fca..694eaabaaebd 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -713,7 +713,15 @@ static void isolate_freepages(struct zone *zone,
/* Found a block suitable for isolating free pages from */
isolated = 0;
- end_pfn = min(pfn + pageblock_nr_pages, zone_end_pfn);
+
+ /*
+ * As pfn may not start aligned, pfn+pageblock_nr_page
+ * may cross a MAX_ORDER_NR_PAGES boundary and miss
+ * a pfn_valid check. Ensure isolate_freepages_block()
+ * only scans within a pageblock
+ */
+ end_pfn = ALIGN(pfn + 1, pageblock_nr_pages);
+ end_pfn = min(end_pfn, zone_end_pfn);
isolated = isolate_freepages_block(cc, pfn, end_pfn,
freelist, false);
nr_freepages += isolated;
diff --git a/mm/dmapool.c b/mm/dmapool.c
index c5ab33bca0a8..da1b0f0b8709 100644
--- a/mm/dmapool.c
+++ b/mm/dmapool.c
@@ -50,7 +50,6 @@ struct dma_pool { /* the pool */
size_t allocation;
size_t boundary;
char name[32];
- wait_queue_head_t waitq;
struct list_head pools;
};
@@ -62,8 +61,6 @@ struct dma_page { /* cacheable header for 'allocation' bytes */
unsigned int offset;
};
-#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
-
static DEFINE_MUTEX(pools_lock);
static ssize_t
@@ -172,7 +169,6 @@ struct dma_pool *dma_pool_create(const char *name, struct device *dev,
retval->size = size;
retval->boundary = boundary;
retval->allocation = allocation;
- init_waitqueue_head(&retval->waitq);
if (dev) {
int ret;
@@ -227,7 +223,6 @@ static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags)
memset(page->vaddr, POOL_POISON_FREED, pool->allocation);
#endif
pool_initialise_page(pool, page);
- list_add(&page->page_list, &pool->page_list);
page->in_use = 0;
page->offset = 0;
} else {
@@ -315,30 +310,21 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
might_sleep_if(mem_flags & __GFP_WAIT);
spin_lock_irqsave(&pool->lock, flags);
- restart:
list_for_each_entry(page, &pool->page_list, page_list) {
if (page->offset < pool->allocation)
goto ready;
}
- page = pool_alloc_page(pool, GFP_ATOMIC);
- if (!page) {
- if (mem_flags & __GFP_WAIT) {
- DECLARE_WAITQUEUE(wait, current);
- __set_current_state(TASK_UNINTERRUPTIBLE);
- __add_wait_queue(&pool->waitq, &wait);
- spin_unlock_irqrestore(&pool->lock, flags);
+ /* pool_alloc_page() might sleep, so temporarily drop &pool->lock */
+ spin_unlock_irqrestore(&pool->lock, flags);
- schedule_timeout(POOL_TIMEOUT_JIFFIES);
+ page = pool_alloc_page(pool, mem_flags);
+ if (!page)
+ return NULL;
- spin_lock_irqsave(&pool->lock, flags);
- __remove_wait_queue(&pool->waitq, &wait);
- goto restart;
- }
- retval = NULL;
- goto done;
- }
+ spin_lock_irqsave(&pool->lock, flags);
+ list_add(&page->page_list, &pool->page_list);
ready:
page->in_use++;
offset = page->offset;
@@ -348,7 +334,6 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
#ifdef DMAPOOL_DEBUG
memset(retval, POOL_POISON_ALLOCATED, pool->size);
#endif
- done:
spin_unlock_irqrestore(&pool->lock, flags);
return retval;
}
@@ -435,8 +420,6 @@ void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma)
page->in_use--;
*(int *)vaddr = page->offset;
page->offset = offset;
- if (waitqueue_active(&pool->waitq))
- wake_up_locked(&pool->waitq);
/*
* Resist a temptation to do
* if (!is_page_busy(page)) pool_free_page(pool, page);
diff --git a/mm/highmem.c b/mm/highmem.c
index d517cd16a6eb..2da13a5c50e2 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -98,7 +98,7 @@ struct page *kmap_to_page(void *vaddr)
{
unsigned long addr = (unsigned long)vaddr;
- if (addr >= PKMAP_ADDR(0) && addr <= PKMAP_ADDR(LAST_PKMAP)) {
+ if (addr >= PKMAP_ADDR(0) && addr < PKMAP_ADDR(LAST_PKMAP)) {
int i = (addr - PKMAP_ADDR(0)) >> PAGE_SHIFT;
return pte_page(pkmap_page_table[i]);
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7acf43bf04a2..dd39ba000b31 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1055,12 +1055,24 @@ struct lruvec *mem_cgroup_zone_lruvec(struct zone *zone,
struct mem_cgroup *memcg)
{
struct mem_cgroup_per_zone *mz;
+ struct lruvec *lruvec;
- if (mem_cgroup_disabled())
- return &zone->lruvec;
+ if (mem_cgroup_disabled()) {
+ lruvec = &zone->lruvec;
+ goto out;
+ }
mz = mem_cgroup_zoneinfo(memcg, zone_to_nid(zone), zone_idx(zone));
- return &mz->lruvec;
+ lruvec = &mz->lruvec;
+out:
+ /*
+ * Since a node can be onlined after the mem_cgroup was created,
+ * we have to be prepared to initialize lruvec->zone here;
+ * and if offlined then reonlined, we need to reinitialize it.
+ */
+ if (unlikely(lruvec->zone != zone))
+ lruvec->zone = zone;
+ return lruvec;
}
/*
@@ -1087,9 +1099,12 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
struct mem_cgroup_per_zone *mz;
struct mem_cgroup *memcg;
struct page_cgroup *pc;
+ struct lruvec *lruvec;
- if (mem_cgroup_disabled())
- return &zone->lruvec;
+ if (mem_cgroup_disabled()) {
+ lruvec = &zone->lruvec;
+ goto out;
+ }
pc = lookup_page_cgroup(page);
memcg = pc->mem_cgroup;
@@ -1107,7 +1122,16 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
pc->mem_cgroup = memcg = root_mem_cgroup;
mz = page_cgroup_zoneinfo(memcg, page);
- return &mz->lruvec;
+ lruvec = &mz->lruvec;
+out:
+ /*
+ * Since a node can be onlined after the mem_cgroup was created,
+ * we have to be prepared to initialize lruvec->zone here;
+ * and if offlined then reonlined, we need to reinitialize it.
+ */
+ if (unlikely(lruvec->zone != zone))
+ lruvec->zone = zone;
+ return lruvec;
}
/**
@@ -1452,17 +1476,26 @@ static int mem_cgroup_count_children(struct mem_cgroup *memcg)
static u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
{
u64 limit;
- u64 memsw;
limit = res_counter_read_u64(&memcg->res, RES_LIMIT);
- limit += total_swap_pages << PAGE_SHIFT;
- memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
/*
- * If memsw is finite and limits the amount of swap space available
- * to this memcg, return that limit.
+ * Do not consider swap space if we cannot swap due to swappiness
*/
- return min(limit, memsw);
+ if (mem_cgroup_swappiness(memcg)) {
+ u64 memsw;
+
+ limit += total_swap_pages << PAGE_SHIFT;
+ memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
+
+ /*
+ * If memsw is finite and limits the amount of swap space
+ * available to this memcg, return that limit.
+ */
+ limit = min(limit, memsw);
+ }
+
+ return limit;
}
void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
@@ -3688,17 +3721,17 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
static bool mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
int node, int zid, enum lru_list lru)
{
- struct mem_cgroup_per_zone *mz;
+ struct lruvec *lruvec;
unsigned long flags, loop;
struct list_head *list;
struct page *busy;
struct zone *zone;
zone = &NODE_DATA(node)->node_zones[zid];
- mz = mem_cgroup_zoneinfo(memcg, node, zid);
- list = &mz->lruvec.lists[lru];
+ lruvec = mem_cgroup_zone_lruvec(zone, memcg);
+ list = &lruvec->lists[lru];
- loop = mz->lru_size[lru];
+ loop = mem_cgroup_get_lru_size(lruvec, lru);
/* give some margin against EBUSY etc...*/
loop += 256;
busy = NULL;
@@ -4736,7 +4769,7 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
for (zone = 0; zone < MAX_NR_ZONES; zone++) {
mz = &pn->zoneinfo[zone];
- lruvec_init(&mz->lruvec, &NODE_DATA(node)->node_zones[zone]);
+ lruvec_init(&mz->lruvec);
mz->usage_in_excess = 0;
mz->on_tree = false;
mz->memcg = memcg;
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 6c5899b9034a..8b20278be6a6 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -1476,9 +1476,17 @@ int soft_offline_page(struct page *page, int flags)
{
int ret;
unsigned long pfn = page_to_pfn(page);
+ struct page *hpage = compound_trans_head(page);
if (PageHuge(page))
return soft_offline_huge_page(page, flags);
+ if (PageTransHuge(hpage)) {
+ if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
+ pr_info("soft offline: %#lx: failed to split THP\n",
+ pfn);
+ return -EBUSY;
+ }
+ }
ret = get_any_page(page, pfn, flags);
if (ret < 0)
diff --git a/mm/memory.c b/mm/memory.c
index fb135ba4aba9..221fc9ffcab1 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2527,9 +2527,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
int ret = 0;
int page_mkwrite = 0;
struct page *dirty_page = NULL;
- unsigned long mmun_start; /* For mmu_notifiers */
- unsigned long mmun_end; /* For mmu_notifiers */
- bool mmun_called = false; /* For mmu_notifiers */
+ unsigned long mmun_start = 0; /* For mmu_notifiers */
+ unsigned long mmun_end = 0; /* For mmu_notifiers */
old_page = vm_normal_page(vma, address, orig_pte);
if (!old_page) {
@@ -2708,8 +2707,7 @@ gotten:
goto oom_free_new;
mmun_start = address & PAGE_MASK;
- mmun_end = (address & PAGE_MASK) + PAGE_SIZE;
- mmun_called = true;
+ mmun_end = mmun_start + PAGE_SIZE;
mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
/*
@@ -2778,7 +2776,7 @@ gotten:
page_cache_release(new_page);
unlock:
pte_unmap_unlock(page_table, ptl);
- if (mmun_called)
+ if (mmun_end > mmun_start)
mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
if (old_page) {
/*
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 56b758ae57d2..e4eeacae2b91 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -106,7 +106,6 @@ static void get_page_bootmem(unsigned long info, struct page *page,
void __ref put_page_bootmem(struct page *page)
{
unsigned long type;
- struct zone *zone;
type = (unsigned long) page->lru.next;
BUG_ON(type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
@@ -117,12 +116,6 @@ void __ref put_page_bootmem(struct page *page)
set_page_private(page, 0);
INIT_LIST_HEAD(&page->lru);
__free_pages_bootmem(page, 0);
-
- zone = page_zone(page);
- zone_span_writelock(zone);
- zone->present_pages++;
- zone_span_writeunlock(zone);
- totalram_pages++;
}
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index d04a8a54c294..4ea600da8940 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -2037,28 +2037,6 @@ struct mempolicy *__mpol_dup(struct mempolicy *old)
return new;
}
-/*
- * If *frompol needs [has] an extra ref, copy *frompol to *tompol ,
- * eliminate the * MPOL_F_* flags that require conditional ref and
- * [NOTE!!!] drop the extra ref. Not safe to reference *frompol directly
- * after return. Use the returned value.
- *
- * Allows use of a mempolicy for, e.g., multiple allocations with a single
- * policy lookup, even if the policy needs/has extra ref on lookup.
- * shmem_readahead needs this.
- */
-struct mempolicy *__mpol_cond_copy(struct mempolicy *tompol,
- struct mempolicy *frompol)
-{
- if (!mpol_needs_cond_ref(frompol))
- return frompol;
-
- *tompol = *frompol;
- tompol->flags &= ~MPOL_F_SHARED; /* copy doesn't need unref */
- __mpol_put(frompol);
- return tompol;
-}
-
/* Slow path of a mempolicy comparison */
bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
{
diff --git a/mm/mmap.c b/mm/mmap.c
index 2d942353d681..9a796c41e7d9 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -334,8 +334,10 @@ void validate_mm(struct mm_struct *mm)
struct vm_area_struct *vma = mm->mmap;
while (vma) {
struct anon_vma_chain *avc;
+ vma_lock_anon_vma(vma);
list_for_each_entry(avc, &vma->anon_vma_chain, same_vma)
anon_vma_interval_tree_verify(avc);
+ vma_unlock_anon_vma(vma);
vma = vma->vm_next;
i++;
}
diff --git a/mm/mmzone.c b/mm/mmzone.c
index 3cef80f6ac79..4596d81b89b1 100644
--- a/mm/mmzone.c
+++ b/mm/mmzone.c
@@ -87,7 +87,7 @@ int memmap_valid_within(unsigned long pfn,
}
#endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */
-void lruvec_init(struct lruvec *lruvec, struct zone *zone)
+void lruvec_init(struct lruvec *lruvec)
{
enum lru_list lru;
@@ -95,8 +95,4 @@ void lruvec_init(struct lruvec *lruvec, struct zone *zone)
for_each_lru(lru)
INIT_LIST_HEAD(&lruvec->lists[lru]);
-
-#ifdef CONFIG_MEMCG
- lruvec->zone = zone;
-#endif
}
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index 714d5d650470..bd82f6b31411 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -116,8 +116,6 @@ static unsigned long __init __free_memory_core(phys_addr_t start,
return 0;
__free_pages_memory(start_pfn, end_pfn);
- fixup_zone_present_pages(pfn_to_nid(start >> PAGE_SHIFT),
- start_pfn, end_pfn);
return end_pfn - start_pfn;
}
@@ -128,7 +126,6 @@ unsigned long __init free_low_memory_core_early(int nodeid)
phys_addr_t start, end, size;
u64 i;
- reset_zone_present_pages();
for_each_free_mem_range(i, MAX_NUMNODES, &start, &end, NULL)
count += __free_memory_core(start, end);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 5b74de6702e0..7e208f0ad68c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1405,7 +1405,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
mt = get_pageblock_migratetype(page);
if (unlikely(mt != MIGRATE_ISOLATE))
- __mod_zone_freepage_state(zone, -(1UL << order), mt);
+ __mod_zone_freepage_state(zone, -(1UL << alloc_order), mt);
if (alloc_order != order)
expand(zone, page, alloc_order, order,
@@ -1422,7 +1422,7 @@ int capture_free_page(struct page *page, int alloc_order, int migratetype)
}
}
- return 1UL << order;
+ return 1UL << alloc_order;
}
/*
@@ -2416,8 +2416,9 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
goto nopage;
restart:
- wake_all_kswapd(order, zonelist, high_zoneidx,
- zone_idx(preferred_zone));
+ if (!(gfp_mask & __GFP_NO_KSWAPD))
+ wake_all_kswapd(order, zonelist, high_zoneidx,
+ zone_idx(preferred_zone));
/*
* OK, we're below the kswapd watermark and have kicked background
@@ -2494,7 +2495,7 @@ rebalance:
* system then fail the allocation instead of entering direct reclaim.
*/
if ((deferred_compaction || contended_compaction) &&
- (gfp_mask & (__GFP_MOVABLE|__GFP_REPEAT)) == __GFP_MOVABLE)
+ (gfp_mask & __GFP_NO_KSWAPD))
goto nopage;
/* Try direct reclaim and then allocating */
@@ -4505,7 +4506,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
zone->zone_pgdat = pgdat;
zone_pcp_init(zone);
- lruvec_init(&zone->lruvec, zone);
+ lruvec_init(&zone->lruvec);
if (!size)
continue;
@@ -6098,37 +6099,3 @@ void dump_page(struct page *page)
dump_page_flags(page->flags);
mem_cgroup_print_bad_page(page);
}
-
-/* reset zone->present_pages */
-void reset_zone_present_pages(void)
-{
- struct zone *z;
- int i, nid;
-
- for_each_node_state(nid, N_HIGH_MEMORY) {
- for (i = 0; i < MAX_NR_ZONES; i++) {
- z = NODE_DATA(nid)->node_zones + i;
- z->present_pages = 0;
- }
- }
-}
-
-/* calculate zone's present pages in buddy system */
-void fixup_zone_present_pages(int nid, unsigned long start_pfn,
- unsigned long end_pfn)
-{
- struct zone *z;
- unsigned long zone_start_pfn, zone_end_pfn;
- int i;
-
- for (i = 0; i < MAX_NR_ZONES; i++) {
- z = NODE_DATA(nid)->node_zones + i;
- zone_start_pfn = z->zone_start_pfn;
- zone_end_pfn = zone_start_pfn + z->spanned_pages;
-
- /* if the two regions intersect */
- if (!(zone_start_pfn >= end_pfn || zone_end_pfn <= start_pfn))
- z->present_pages += min(end_pfn, zone_end_pfn) -
- max(start_pfn, zone_start_pfn);
- }
-}
diff --git a/mm/shmem.c b/mm/shmem.c
index 67afba5117f2..50c5b8f3a359 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -643,7 +643,7 @@ static void shmem_evict_inode(struct inode *inode)
kfree(info->symlink);
simple_xattrs_free(&info->xattrs);
- BUG_ON(inode->i_blocks);
+ WARN_ON(inode->i_blocks);
shmem_free_inode(inode->i_sb);
clear_inode(inode);
}
@@ -910,25 +910,29 @@ static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo)
static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
{
- struct mempolicy mpol, *spol;
struct vm_area_struct pvma;
-
- spol = mpol_cond_copy(&mpol,
- mpol_shared_policy_lookup(&info->policy, index));
+ struct page *page;
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
/* Bias interleave by inode number to distribute better across nodes */
pvma.vm_pgoff = index + info->vfs_inode.i_ino;
pvma.vm_ops = NULL;
- pvma.vm_policy = spol;
- return swapin_readahead(swap, gfp, &pvma, 0);
+ pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
+
+ page = swapin_readahead(swap, gfp, &pvma, 0);
+
+ /* Drop reference taken by mpol_shared_policy_lookup() */
+ mpol_cond_put(pvma.vm_policy);
+
+ return page;
}
static struct page *shmem_alloc_page(gfp_t gfp,
struct shmem_inode_info *info, pgoff_t index)
{
struct vm_area_struct pvma;
+ struct page *page;
/* Create a pseudo vma that just contains the policy */
pvma.vm_start = 0;
@@ -937,10 +941,12 @@ static struct page *shmem_alloc_page(gfp_t gfp,
pvma.vm_ops = NULL;
pvma.vm_policy = mpol_shared_policy_lookup(&info->policy, index);
- /*
- * alloc_page_vma() will drop the shared policy reference
- */
- return alloc_page_vma(gfp, &pvma, 0);
+ page = alloc_page_vma(gfp, &pvma, 0);
+
+ /* Drop reference taken by mpol_shared_policy_lookup() */
+ mpol_cond_put(pvma.vm_policy);
+
+ return page;
}
#else /* !CONFIG_NUMA */
#ifdef CONFIG_TMPFS
@@ -1145,8 +1151,20 @@ repeat:
if (!error) {
error = shmem_add_to_page_cache(page, mapping, index,
gfp, swp_to_radix_entry(swap));
- /* We already confirmed swap, and make no allocation */
- VM_BUG_ON(error);
+ /*
+ * We already confirmed swap under page lock, and make
+ * no memory allocation here, so usually no possibility
+ * of error; but free_swap_and_cache() only trylocks a
+ * page, so it is just possible that the entry has been
+ * truncated or holepunched since swap was confirmed.
+ * shmem_undo_range() will have done some of the
+ * unaccounting, now delete_from_swap_cache() will do
+ * the rest (including mem_cgroup_uncharge_swapcache).
+ * Reset swap.val? No, leave it so "failed" goes back to
+ * "repeat": reading a hole and writing should succeed.
+ */
+ if (error)
+ delete_from_swap_cache(page);
}
if (error)
goto failed;
diff --git a/mm/sparse.c b/mm/sparse.c
index fac95f2888f2..a83de2f72b30 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -617,7 +617,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
{
return; /* XXX: Not implemented yet */
}
-static void free_map_bootmem(struct page *page, unsigned long nr_pages)
+static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
{
}
#else
@@ -658,10 +658,11 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
get_order(sizeof(struct page) * nr_pages));
}
-static void free_map_bootmem(struct page *page, unsigned long nr_pages)
+static void free_map_bootmem(struct page *memmap, unsigned long nr_pages)
{
unsigned long maps_section_nr, removing_section_nr, i;
unsigned long magic;
+ struct page *page = virt_to_page(memmap);
for (i = 0; i < nr_pages; i++, page++) {
magic = (unsigned long) page->lru.next;
@@ -710,13 +711,10 @@ static void free_section_usemap(struct page *memmap, unsigned long *usemap)
*/
if (memmap) {
- struct page *memmap_page;
- memmap_page = virt_to_page(memmap);
-
nr_pages = PAGE_ALIGN(PAGES_PER_SECTION * sizeof(struct page))
>> PAGE_SHIFT;
- free_map_bootmem(memmap_page, nr_pages);
+ free_map_bootmem(memmap, nr_pages);
}
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 71cd288b2001..f91a25547ffe 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1494,9 +1494,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
BUG_ON(!current->mm);
pathname = getname(specialfile);
- err = PTR_ERR(pathname);
if (IS_ERR(pathname))
- goto out;
+ return PTR_ERR(pathname);
victim = file_open_name(pathname, O_RDWR|O_LARGEFILE, 0);
err = PTR_ERR(victim);
@@ -1608,6 +1607,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
out_dput:
filp_close(victim, NULL);
out:
+ putname(pathname);
return err;
}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 8b055e9379bc..b7ed37675644 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1760,28 +1760,6 @@ static bool in_reclaim_compaction(struct scan_control *sc)
return false;
}
-#ifdef CONFIG_COMPACTION
-/*
- * If compaction is deferred for sc->order then scale the number of pages
- * reclaimed based on the number of consecutive allocation failures
- */
-static unsigned long scale_for_compaction(unsigned long pages_for_compaction,
- struct lruvec *lruvec, struct scan_control *sc)
-{
- struct zone *zone = lruvec_zone(lruvec);
-
- if (zone->compact_order_failed <= sc->order)
- pages_for_compaction <<= zone->compact_defer_shift;
- return pages_for_compaction;
-}
-#else
-static unsigned long scale_for_compaction(unsigned long pages_for_compaction,
- struct lruvec *lruvec, struct scan_control *sc)
-{
- return pages_for_compaction;
-}
-#endif
-
/*
* Reclaim/compaction is used for high-order allocation requests. It reclaims
* order-0 pages before compacting the zone. should_continue_reclaim() returns
@@ -1829,9 +1807,6 @@ static inline bool should_continue_reclaim(struct lruvec *lruvec,
* inactive lists are large enough, continue reclaiming
*/
pages_for_compaction = (2UL << sc->order);
-
- pages_for_compaction = scale_for_compaction(pages_for_compaction,
- lruvec, sc);
inactive_lru_pages = get_lru_size(lruvec, LRU_INACTIVE_FILE);
if (nr_swap_pages > 0)
inactive_lru_pages += get_lru_size(lruvec, LRU_INACTIVE_ANON);
@@ -2232,9 +2207,12 @@ static bool pfmemalloc_watermark_ok(pg_data_t *pgdat)
* Throttle direct reclaimers if backing storage is backed by the network
* and the PFMEMALLOC reserve for the preferred node is getting dangerously
* depleted. kswapd will continue to make progress and wake the processes
- * when the low watermark is reached
+ * when the low watermark is reached.
+ *
+ * Returns true if a fatal signal was delivered during throttling. If this
+ * happens, the page allocator should not consider triggering the OOM killer.
*/
-static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
+static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
nodemask_t *nodemask)
{
struct zone *zone;
@@ -2249,13 +2227,20 @@ static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
* processes to block on log_wait_commit().
*/
if (current->flags & PF_KTHREAD)
- return;
+ goto out;
+
+ /*
+ * If a fatal signal is pending, this process should not throttle.
+ * It should return quickly so it can exit and free its memory
+ */
+ if (fatal_signal_pending(current))
+ goto out;
/* Check if the pfmemalloc reserves are ok */
first_zones_zonelist(zonelist, high_zoneidx, NULL, &zone);
pgdat = zone->zone_pgdat;
if (pfmemalloc_watermark_ok(pgdat))
- return;
+ goto out;
/* Account for the throttling */
count_vm_event(PGSCAN_DIRECT_THROTTLE);
@@ -2271,12 +2256,20 @@ static void throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
if (!(gfp_mask & __GFP_FS)) {
wait_event_interruptible_timeout(pgdat->pfmemalloc_wait,
pfmemalloc_watermark_ok(pgdat), HZ);
- return;
+
+ goto check_pending;
}
/* Throttle until kswapd wakes the process */
wait_event_killable(zone->zone_pgdat->pfmemalloc_wait,
pfmemalloc_watermark_ok(pgdat));
+
+check_pending:
+ if (fatal_signal_pending(current))
+ return true;
+
+out:
+ return false;
}
unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
@@ -2298,13 +2291,12 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
.gfp_mask = sc.gfp_mask,
};
- throttle_direct_reclaim(gfp_mask, zonelist, nodemask);
-
/*
- * Do not enter reclaim if fatal signal is pending. 1 is returned so
- * that the page allocator does not consider triggering OOM
+ * Do not enter reclaim if fatal signal was delivered while throttled.
+ * 1 is returned so that the page allocator does not OOM kill at this
+ * point.
*/
- if (fatal_signal_pending(current))
+ if (throttle_direct_reclaim(gfp_mask, zonelist, nodemask))
return 1;
trace_mm_vmscan_direct_reclaim_begin(order,
@@ -2422,6 +2414,19 @@ static void age_active_anon(struct zone *zone, struct scan_control *sc)
} while (memcg);
}
+static bool zone_balanced(struct zone *zone, int order,
+ unsigned long balance_gap, int classzone_idx)
+{
+ if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone) +
+ balance_gap, classzone_idx, 0))
+ return false;
+
+ if (COMPACTION_BUILD && order && !compaction_suitable(zone, order))
+ return false;
+
+ return true;
+}
+
/*
* pgdat_balanced is used when checking if a node is balanced for high-order
* allocations. Only zones that meet watermarks and are in a zone allowed
@@ -2500,8 +2505,7 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
continue;
}
- if (!zone_watermark_ok_safe(zone, order, high_wmark_pages(zone),
- i, 0))
+ if (!zone_balanced(zone, order, 0, i))
all_zones_ok = false;
else
balanced += zone->present_pages;
@@ -2610,8 +2614,7 @@ loop_again:
break;
}
- if (!zone_watermark_ok_safe(zone, order,
- high_wmark_pages(zone), 0, 0)) {
+ if (!zone_balanced(zone, order, 0, 0)) {
end_zone = i;
break;
} else {
@@ -2687,9 +2690,8 @@ loop_again:
testorder = 0;
if ((buffer_heads_over_limit && is_highmem_idx(i)) ||
- !zone_watermark_ok_safe(zone, testorder,
- high_wmark_pages(zone) + balance_gap,
- end_zone, 0)) {
+ !zone_balanced(zone, testorder,
+ balance_gap, end_zone)) {
shrink_zone(zone, &sc);
reclaim_state->reclaimed_slab = 0;
@@ -2716,8 +2718,7 @@ loop_again:
continue;
}
- if (!zone_watermark_ok_safe(zone, testorder,
- high_wmark_pages(zone), end_zone, 0)) {
+ if (!zone_balanced(zone, testorder, 0, end_zone)) {
all_zones_ok = 0;
/*
* We are still under min water mark. This
@@ -2822,29 +2823,10 @@ out:
if (!populated_zone(zone))
continue;
- if (zone->all_unreclaimable &&
- sc.priority != DEF_PRIORITY)
- continue;
-
- /* Would compaction fail due to lack of free memory? */
- if (COMPACTION_BUILD &&
- compaction_suitable(zone, order) == COMPACT_SKIPPED)
- goto loop_again;
-
- /* Confirm the zone is balanced for order-0 */
- if (!zone_watermark_ok(zone, 0,
- high_wmark_pages(zone), 0, 0)) {
- order = sc.order = 0;
- goto loop_again;
- }
-
/* Check if the memory needs to be defragmented. */
if (zone_watermark_ok(zone, order,
low_wmark_pages(zone), *classzone_idx, 0))
zones_need_compaction = 0;
-
- /* If balanced, clear the congested flag */
- zone_clear_flag(zone, ZONE_CONGESTED);
}
if (zones_need_compaction)
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index b9a28d2dd3e8..ce0684a1fc83 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -325,6 +325,12 @@ void batadv_interface_rx(struct net_device *soft_iface,
soft_iface->last_rx = jiffies;
+ /* Let the bridge loop avoidance check the packet. If will
+ * not handle it, we can safely push it up.
+ */
+ if (batadv_bla_rx(bat_priv, skb, vid, is_bcast))
+ goto out;
+
if (orig_node)
batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
ethhdr->h_source);
@@ -332,12 +338,6 @@ void batadv_interface_rx(struct net_device *soft_iface,
if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
goto dropped;
- /* Let the bridge loop avoidance check the packet. If will
- * not handle it, we can safely push it up.
- */
- if (batadv_bla_rx(bat_priv, skb, vid, is_bcast))
- goto out;
-
netif_rx(skb);
goto out;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 112edd371b2f..baae71585804 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -769,6 +769,12 @@ int batadv_tt_global_add(struct batadv_priv *bat_priv,
*/
tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_TEMP;
+ /* the change can carry possible "attribute" flags like the
+ * TT_CLIENT_WIFI, therefore they have to be copied in the
+ * client entry
+ */
+ tt_global_entry->common.flags |= flags;
+
/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only
* one originator left in the list and we previously received a
* delete + roaming change for this originator.
@@ -1496,7 +1502,7 @@ batadv_tt_response_fill_table(uint16_t tt_len, uint8_t ttvn,
memcpy(tt_change->addr, tt_common_entry->addr,
ETH_ALEN);
- tt_change->flags = BATADV_NO_FLAGS;
+ tt_change->flags = tt_common_entry->flags;
tt_count++;
tt_change++;
@@ -2450,6 +2456,13 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
{
bool ret = false;
+ /* if the originator is a backbone node (meaning it belongs to the same
+ * LAN of this node) the temporary client must not be added because to
+ * reach such destination the node must use the LAN instead of the mesh
+ */
+ if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
+ goto out;
+
if (!batadv_tt_global_add(bat_priv, orig_node, addr,
BATADV_TT_CLIENT_TEMP,
atomic_read(&orig_node->last_ttvn)))
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 8a0ce706aebd..a0a2f97b9c62 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1754,11 +1754,11 @@ int hci_register_dev(struct hci_dev *hdev)
if (hdev->dev_type != HCI_AMP)
set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
- schedule_work(&hdev->power_on);
-
hci_notify(hdev, HCI_DEV_REG);
hci_dev_hold(hdev);
+ schedule_work(&hdev->power_on);
+
return id;
err_wqueue:
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index aa2ea0a8142c..91de4239da66 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -326,7 +326,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
struct hci_dev *d;
size_t rp_len;
u16 count;
- int i, err;
+ int err;
BT_DBG("sock %p", sk);
@@ -347,9 +347,7 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
return -ENOMEM;
}
- rp->num_controllers = cpu_to_le16(count);
-
- i = 0;
+ count = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (test_bit(HCI_SETUP, &d->dev_flags))
continue;
@@ -357,10 +355,13 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
if (!mgmt_valid_hdev(d))
continue;
- rp->index[i++] = cpu_to_le16(d->id);
+ rp->index[count++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
+ rp->num_controllers = cpu_to_le16(count);
+ rp_len = sizeof(*rp) + (2 * count);
+
read_unlock(&hci_dev_list_lock);
err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
@@ -1366,6 +1367,7 @@ static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
continue;
list_del(&match->list);
+ kfree(match);
found++;
}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 2ac8d50861e0..a5923378bdf0 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -267,7 +267,7 @@ static void smp_failure(struct l2cap_conn *conn, u8 reason, u8 send)
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->hcon->flags);
mgmt_auth_failed(conn->hcon->hdev, conn->dst, hcon->type,
- hcon->dst_type, reason);
+ hcon->dst_type, HCI_ERROR_AUTH_FAILURE);
cancel_delayed_work_sync(&conn->security_timer);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 6f747582718e..969b7cdff59d 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1084,6 +1084,9 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
op->sk = sk;
op->ifindex = ifindex;
+ /* ifindex for timeout events w/o previous frame reception */
+ op->rx_ifindex = ifindex;
+
/* initialize uninitialized (kzalloc) structure */
hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
op->timer.function = bcm_rx_timeout_handler;
diff --git a/net/core/dev.c b/net/core/dev.c
index bda6d004f9f0..e5942bf45a6d 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2818,8 +2818,10 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
if (unlikely(tcpu != next_cpu) &&
(tcpu == RPS_NO_CPU || !cpu_online(tcpu) ||
((int)(per_cpu(softnet_data, tcpu).input_queue_head -
- rflow->last_qtail)) >= 0))
+ rflow->last_qtail)) >= 0)) {
+ tcpu = next_cpu;
rflow = set_rps_cpu(dev, skb, rflow, next_cpu);
+ }
if (tcpu != RPS_NO_CPU && cpu_online(tcpu)) {
*rflowp = rflow;
@@ -3449,6 +3451,8 @@ static int napi_gro_complete(struct sk_buff *skb)
struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
int err = -ENOENT;
+ BUILD_BUG_ON(sizeof(struct napi_gro_cb) > sizeof(skb->cb));
+
if (NAPI_GRO_CB(skb)->count == 1) {
skb_shinfo(skb)->gso_size = 0;
goto out;
diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c
index 87cc17db2d56..b079c7bbc157 100644
--- a/net/core/dev_addr_lists.c
+++ b/net/core/dev_addr_lists.c
@@ -319,7 +319,8 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr,
*/
ha = list_first_entry(&dev->dev_addrs.list,
struct netdev_hw_addr, list);
- if (ha->addr == dev->dev_addr && ha->refcount == 1)
+ if (!memcmp(ha->addr, addr, dev->addr_len) &&
+ ha->type == addr_type && ha->refcount == 1)
return -ENOENT;
err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index bcf02f608cbf..017a8bacfb27 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -429,6 +429,17 @@ static struct attribute_group netstat_group = {
.name = "statistics",
.attrs = netstat_attrs,
};
+
+#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211)
+static struct attribute *wireless_attrs[] = {
+ NULL
+};
+
+static struct attribute_group wireless_group = {
+ .name = "wireless",
+ .attrs = wireless_attrs,
+};
+#endif
#endif /* CONFIG_SYSFS */
#ifdef CONFIG_RPS
@@ -1409,6 +1420,15 @@ int netdev_register_kobject(struct net_device *net)
groups++;
*groups++ = &netstat_group;
+
+#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211)
+ if (net->ieee80211_ptr)
+ *groups++ = &wireless_group;
+#if IS_ENABLED(CONFIG_WIRELESS_EXT)
+ else if (net->wireless_handlers)
+ *groups++ = &wireless_group;
+#endif
+#endif
#endif /* CONFIG_SYSFS */
error = device_add(dev);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 4007c1437fda..3f0636cd76cd 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3004,7 +3004,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
skb_shinfo(nskb)->gso_size = pinfo->gso_size;
pinfo->gso_size = 0;
skb_header_release(p);
- nskb->prev = p;
+ NAPI_GRO_CB(nskb)->last = p;
nskb->data_len += p->len;
nskb->truesize += p->truesize;
@@ -3030,8 +3030,8 @@ merge:
__skb_pull(skb, offset);
- p->prev->next = skb;
- p->prev = skb;
+ NAPI_GRO_CB(p)->last->next = skb;
+ NAPI_GRO_CB(p)->last = skb;
skb_header_release(skb);
done:
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index f2eccd531746..17ff9fd7cdda 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -257,7 +257,8 @@ static inline bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
struct inet_peer *peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1);
rc = inet_peer_xrlim_allow(peer,
net->ipv4.sysctl_icmp_ratelimit);
- inet_putpeer(peer);
+ if (peer)
+ inet_putpeer(peer);
}
out:
return rc;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 0c34bfabc11f..e23e16dc501d 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -44,6 +44,10 @@ struct inet_diag_entry {
u16 dport;
u16 family;
u16 userlocks;
+#if IS_ENABLED(CONFIG_IPV6)
+ struct in6_addr saddr_storage; /* for IPv4-mapped-IPv6 addresses */
+ struct in6_addr daddr_storage; /* for IPv4-mapped-IPv6 addresses */
+#endif
};
static DEFINE_MUTEX(inet_diag_table_mutex);
@@ -428,25 +432,31 @@ static int inet_diag_bc_run(const struct nlattr *_bc,
break;
}
- if (cond->prefix_len == 0)
- break;
-
if (op->code == INET_DIAG_BC_S_COND)
addr = entry->saddr;
else
addr = entry->daddr;
+ if (cond->family != AF_UNSPEC &&
+ cond->family != entry->family) {
+ if (entry->family == AF_INET6 &&
+ cond->family == AF_INET) {
+ if (addr[0] == 0 && addr[1] == 0 &&
+ addr[2] == htonl(0xffff) &&
+ bitstring_match(addr + 3,
+ cond->addr,
+ cond->prefix_len))
+ break;
+ }
+ yes = 0;
+ break;
+ }
+
+ if (cond->prefix_len == 0)
+ break;
if (bitstring_match(addr, cond->addr,
cond->prefix_len))
break;
- if (entry->family == AF_INET6 &&
- cond->family == AF_INET) {
- if (addr[0] == 0 && addr[1] == 0 &&
- addr[2] == htonl(0xffff) &&
- bitstring_match(addr + 3, cond->addr,
- cond->prefix_len))
- break;
- }
yes = 0;
break;
}
@@ -509,6 +519,55 @@ static int valid_cc(const void *bc, int len, int cc)
return 0;
}
+/* Validate an inet_diag_hostcond. */
+static bool valid_hostcond(const struct inet_diag_bc_op *op, int len,
+ int *min_len)
+{
+ int addr_len;
+ struct inet_diag_hostcond *cond;
+
+ /* Check hostcond space. */
+ *min_len += sizeof(struct inet_diag_hostcond);
+ if (len < *min_len)
+ return false;
+ cond = (struct inet_diag_hostcond *)(op + 1);
+
+ /* Check address family and address length. */
+ switch (cond->family) {
+ case AF_UNSPEC:
+ addr_len = 0;
+ break;
+ case AF_INET:
+ addr_len = sizeof(struct in_addr);
+ break;
+ case AF_INET6:
+ addr_len = sizeof(struct in6_addr);
+ break;
+ default:
+ return false;
+ }
+ *min_len += addr_len;
+ if (len < *min_len)
+ return false;
+
+ /* Check prefix length (in bits) vs address length (in bytes). */
+ if (cond->prefix_len > 8 * addr_len)
+ return false;
+
+ return true;
+}
+
+/* Validate a port comparison operator. */
+static inline bool valid_port_comparison(const struct inet_diag_bc_op *op,
+ int len, int *min_len)
+{
+ /* Port comparisons put the port in a follow-on inet_diag_bc_op. */
+ *min_len += sizeof(struct inet_diag_bc_op);
+ if (len < *min_len)
+ return false;
+ return true;
+}
+
static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
{
const void *bc = bytecode;
@@ -516,29 +575,39 @@ static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
while (len > 0) {
const struct inet_diag_bc_op *op = bc;
+ int min_len = sizeof(struct inet_diag_bc_op);
//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
switch (op->code) {
- case INET_DIAG_BC_AUTO:
case INET_DIAG_BC_S_COND:
case INET_DIAG_BC_D_COND:
+ if (!valid_hostcond(bc, len, &min_len))
+ return -EINVAL;
+ break;
case INET_DIAG_BC_S_GE:
case INET_DIAG_BC_S_LE:
case INET_DIAG_BC_D_GE:
case INET_DIAG_BC_D_LE:
- case INET_DIAG_BC_JMP:
- if (op->no < 4 || op->no > len + 4 || op->no & 3)
- return -EINVAL;
- if (op->no < len &&
- !valid_cc(bytecode, bytecode_len, len - op->no))
+ if (!valid_port_comparison(bc, len, &min_len))
return -EINVAL;
break;
+ case INET_DIAG_BC_AUTO:
+ case INET_DIAG_BC_JMP:
case INET_DIAG_BC_NOP:
break;
default:
return -EINVAL;
}
- if (op->yes < 4 || op->yes > len + 4 || op->yes & 3)
+
+ if (op->code != INET_DIAG_BC_NOP) {
+ if (op->no < min_len || op->no > len + 4 || op->no & 3)
+ return -EINVAL;
+ if (op->no < len &&
+ !valid_cc(bytecode, bytecode_len, len - op->no))
+ return -EINVAL;
+ }
+
+ if (op->yes < min_len || op->yes > len + 4 || op->yes & 3)
return -EINVAL;
bc += op->yes;
len -= op->yes;
@@ -596,6 +665,36 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
}
+/* Get the IPv4, IPv6, or IPv4-mapped-IPv6 local and remote addresses
+ * from a request_sock. For IPv4-mapped-IPv6 we must map IPv4 to IPv6.
+ */
+static inline void inet_diag_req_addrs(const struct sock *sk,
+ const struct request_sock *req,
+ struct inet_diag_entry *entry)
+{
+ struct inet_request_sock *ireq = inet_rsk(req);
+
+#if IS_ENABLED(CONFIG_IPV6)
+ if (sk->sk_family == AF_INET6) {
+ if (req->rsk_ops->family == AF_INET6) {
+ entry->saddr = inet6_rsk(req)->loc_addr.s6_addr32;
+ entry->daddr = inet6_rsk(req)->rmt_addr.s6_addr32;
+ } else if (req->rsk_ops->family == AF_INET) {
+ ipv6_addr_set_v4mapped(ireq->loc_addr,
+ &entry->saddr_storage);
+ ipv6_addr_set_v4mapped(ireq->rmt_addr,
+ &entry->daddr_storage);
+ entry->saddr = entry->saddr_storage.s6_addr32;
+ entry->daddr = entry->daddr_storage.s6_addr32;
+ }
+ } else
+#endif
+ {
+ entry->saddr = &ireq->loc_addr;
+ entry->daddr = &ireq->rmt_addr;
+ }
+}
+
static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
struct request_sock *req,
struct user_namespace *user_ns,
@@ -637,8 +736,10 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
r->idiag_inode = 0;
#if IS_ENABLED(CONFIG_IPV6)
if (r->idiag_family == AF_INET6) {
- *(struct in6_addr *)r->id.idiag_src = inet6_rsk(req)->loc_addr;
- *(struct in6_addr *)r->id.idiag_dst = inet6_rsk(req)->rmt_addr;
+ struct inet_diag_entry entry;
+ inet_diag_req_addrs(sk, req, &entry);
+ memcpy(r->id.idiag_src, entry.saddr, sizeof(struct in6_addr));
+ memcpy(r->id.idiag_dst, entry.daddr, sizeof(struct in6_addr));
}
#endif
@@ -691,18 +792,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
continue;
if (bc) {
- entry.saddr =
-#if IS_ENABLED(CONFIG_IPV6)
- (entry.family == AF_INET6) ?
- inet6_rsk(req)->loc_addr.s6_addr32 :
-#endif
- &ireq->loc_addr;
- entry.daddr =
-#if IS_ENABLED(CONFIG_IPV6)
- (entry.family == AF_INET6) ?
- inet6_rsk(req)->rmt_addr.s6_addr32 :
-#endif
- &ireq->rmt_addr;
+ inet_diag_req_addrs(sk, req, &entry);
entry.dport = ntohs(ireq->rmt_port);
if (!inet_diag_bc_run(bc, &entry))
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 448e68546827..8d5cc75dac88 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -707,28 +707,27 @@ EXPORT_SYMBOL(ip_defrag);
struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user)
{
- const struct iphdr *iph;
+ struct iphdr iph;
u32 len;
if (skb->protocol != htons(ETH_P_IP))
return skb;
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ if (!skb_copy_bits(skb, 0, &iph, sizeof(iph)))
return skb;
- iph = ip_hdr(skb);
- if (iph->ihl < 5 || iph->version != 4)
+ if (iph.ihl < 5 || iph.version != 4)
return skb;
- if (!pskb_may_pull(skb, iph->ihl*4))
- return skb;
- iph = ip_hdr(skb);
- len = ntohs(iph->tot_len);
- if (skb->len < len || len < (iph->ihl * 4))
+
+ len = ntohs(iph.tot_len);
+ if (skb->len < len || len < (iph.ihl * 4))
return skb;
- if (ip_is_fragment(ip_hdr(skb))) {
+ if (ip_is_fragment(&iph)) {
skb = skb_share_check(skb, GFP_ATOMIC);
if (skb) {
+ if (!pskb_may_pull(skb, iph.ihl*4))
+ return skb;
if (pskb_trim_rcsum(skb, len))
return skb;
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 5eea4a811042..14bbfcf717ac 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -457,19 +457,28 @@ static int do_ip_setsockopt(struct sock *sk, int level,
struct inet_sock *inet = inet_sk(sk);
int val = 0, err;
- if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
- (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
- (1<<IP_RETOPTS) | (1<<IP_TOS) |
- (1<<IP_TTL) | (1<<IP_HDRINCL) |
- (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
- (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
- (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT) |
- (1<<IP_MINTTL) | (1<<IP_NODEFRAG))) ||
- optname == IP_UNICAST_IF ||
- optname == IP_MULTICAST_TTL ||
- optname == IP_MULTICAST_ALL ||
- optname == IP_MULTICAST_LOOP ||
- optname == IP_RECVORIGDSTADDR) {
+ switch (optname) {
+ case IP_PKTINFO:
+ case IP_RECVTTL:
+ case IP_RECVOPTS:
+ case IP_RECVTOS:
+ case IP_RETOPTS:
+ case IP_TOS:
+ case IP_TTL:
+ case IP_HDRINCL:
+ case IP_MTU_DISCOVER:
+ case IP_RECVERR:
+ case IP_ROUTER_ALERT:
+ case IP_FREEBIND:
+ case IP_PASSSEC:
+ case IP_TRANSPARENT:
+ case IP_MINTTL:
+ case IP_NODEFRAG:
+ case IP_UNICAST_IF:
+ case IP_MULTICAST_TTL:
+ case IP_MULTICAST_ALL:
+ case IP_MULTICAST_LOOP:
+ case IP_RECVORIGDSTADDR:
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
return -EFAULT;
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c
index 1831092f999f..858fddf6482a 100644
--- a/net/ipv4/ip_vti.c
+++ b/net/ipv4/ip_vti.c
@@ -338,12 +338,17 @@ static int vti_rcv(struct sk_buff *skb)
if (tunnel != NULL) {
struct pcpu_tstats *tstats;
+ if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb))
+ return -1;
+
tstats = this_cpu_ptr(tunnel->dev->tstats);
u64_stats_update_begin(&tstats->syncp);
tstats->rx_packets++;
tstats->rx_bytes += skb->len;
u64_stats_update_end(&tstats->syncp);
+ skb->mark = 0;
+ secpath_reset(skb);
skb->dev = tunnel->dev;
return 1;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 6168c4dc58b1..3eab2b2ffd34 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1318,6 +1318,10 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsi
if (get_user(v, (u32 __user *)optval))
return -EFAULT;
+ /* "pimreg%u" should not exceed 16 bytes (IFNAMSIZ) */
+ if (v != RT_TABLE_DEFAULT && v >= 1000000000)
+ return -EINVAL;
+
rtnl_lock();
ret = 0;
if (sk == rtnl_dereference(mrt->mroute_sk)) {
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index a8c651216fa6..df251424d816 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1785,6 +1785,7 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
if (dev_out->flags & IFF_LOOPBACK)
flags |= RTCF_LOCAL;
+ do_cache = true;
if (type == RTN_BROADCAST) {
flags |= RTCF_BROADCAST | RTCF_LOCAL;
fi = NULL;
@@ -1793,6 +1794,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr,
fl4->flowi4_proto))
flags &= ~RTCF_LOCAL;
+ else
+ do_cache = false;
/* If multicast route do not exist use
* default one, but do not gateway in this case.
* Yes, it is hack.
@@ -1802,8 +1805,8 @@ static struct rtable *__mkroute_output(const struct fib_result *res,
}
fnhe = NULL;
- do_cache = fi != NULL;
- if (fi) {
+ do_cache &= fi != NULL;
+ if (do_cache) {
struct rtable __rcu **prth;
struct fib_nh *nh = &FIB_RES_NH(*res);
@@ -2597,7 +2600,7 @@ int __init ip_rt_init(void)
pr_err("Unable to create route proc files\n");
#ifdef CONFIG_XFRM
xfrm_init();
- xfrm4_init(ip_rt_max_size);
+ xfrm4_init();
#endif
rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 197c0008503c..e457c7ab2e28 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -830,8 +830,8 @@ static int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
return mss_now;
}
-static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
- size_t psize, int flags)
+static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
+ size_t size, int flags)
{
struct tcp_sock *tp = tcp_sk(sk);
int mss_now, size_goal;
@@ -858,12 +858,9 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
goto out_err;
- while (psize > 0) {
+ while (size > 0) {
struct sk_buff *skb = tcp_write_queue_tail(sk);
- struct page *page = pages[poffset / PAGE_SIZE];
int copy, i;
- int offset = poffset % PAGE_SIZE;
- int size = min_t(size_t, psize, PAGE_SIZE - offset);
bool can_coalesce;
if (!tcp_send_head(sk) || (copy = size_goal - skb->len) <= 0) {
@@ -912,8 +909,8 @@ new_segment:
TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH;
copied += copy;
- poffset += copy;
- if (!(psize -= copy))
+ offset += copy;
+ if (!(size -= copy))
goto out;
if (skb->len < size_goal || (flags & MSG_OOB))
@@ -960,7 +957,7 @@ int tcp_sendpage(struct sock *sk, struct page *page, int offset,
flags);
lock_sock(sk);
- res = do_tcp_sendpages(sk, &page, offset, size, flags);
+ res = do_tcp_sendpages(sk, page, offset, size, flags);
release_sock(sk);
return res;
}
@@ -1212,7 +1209,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied && likely(!tp->repair))
+ if (copied)
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
@@ -1223,7 +1220,7 @@ wait_for_memory:
}
out:
- if (copied && likely(!tp->repair))
+ if (copied)
tcp_push(sk, flags, mss_now, tp->nonagle);
release_sock(sk);
return copied + copied_syn;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 2c2b13a999ea..181fc8234a52 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5313,11 +5313,6 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
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);
-
/* step 3: check security and precedence [ignored] */
/* step 4: Check for a SYN
@@ -5552,6 +5547,11 @@ step5:
if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 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. */
@@ -5645,7 +5645,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
tcp_fastopen_cache_set(sk, mss, cookie, syn_drop);
if (data) { /* Retransmit unacked data in SYN */
- tcp_retransmit_skb(sk, data);
+ tcp_for_write_queue_from(data, sk) {
+ if (data == tcp_send_head(sk) ||
+ __tcp_retransmit_skb(sk, data))
+ break;
+ }
tcp_rearm_rto(sk);
return true;
}
@@ -6130,6 +6134,11 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
} else
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);
+
/* step 6: check the URG bit */
tcp_urg(sk, skb, th);
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c
index 53bc5847bfa8..f696d7c2e9fa 100644
--- a/net/ipv4/tcp_metrics.c
+++ b/net/ipv4/tcp_metrics.c
@@ -1,7 +1,6 @@
#include <linux/rcupdate.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
-#include <linux/bootmem.h>
#include <linux/module.h>
#include <linux/cache.h>
#include <linux/slab.h>
@@ -9,6 +8,7 @@
#include <linux/tcp.h>
#include <linux/hash.h>
#include <linux/tcp_metrics.h>
+#include <linux/vmalloc.h>
#include <net/inet_connection_sock.h>
#include <net/net_namespace.h>
@@ -1034,7 +1034,10 @@ static int __net_init tcp_net_metrics_init(struct net *net)
net->ipv4.tcp_metrics_hash_log = order_base_2(slots);
size = sizeof(struct tcpm_hash_bucket) << net->ipv4.tcp_metrics_hash_log;
- net->ipv4.tcp_metrics_hash = kzalloc(size, GFP_KERNEL);
+ net->ipv4.tcp_metrics_hash = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+ if (!net->ipv4.tcp_metrics_hash)
+ net->ipv4.tcp_metrics_hash = vzalloc(size);
+
if (!net->ipv4.tcp_metrics_hash)
return -ENOMEM;
@@ -1055,7 +1058,10 @@ static void __net_exit tcp_net_metrics_exit(struct net *net)
tm = next;
}
}
- kfree(net->ipv4.tcp_metrics_hash);
+ if (is_vmalloc_addr(net->ipv4.tcp_metrics_hash))
+ vfree(net->ipv4.tcp_metrics_hash);
+ else
+ kfree(net->ipv4.tcp_metrics_hash);
}
static __net_initdata struct pernet_operations tcp_net_metrics_ops = {
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index cfe6ffe1c177..948ac275b9b5 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -1986,6 +1986,9 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
tso_segs = tcp_init_tso_segs(sk, skb, mss_now);
BUG_ON(!tso_segs);
+ if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE)
+ goto repair; /* Skip network transmission */
+
cwnd_quota = tcp_cwnd_test(tp, skb);
if (!cwnd_quota)
break;
@@ -2026,6 +2029,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp)))
break;
+repair:
/* Advance the send_head. This one is sent out.
* This call will increment packets_out.
*/
@@ -2305,12 +2309,11 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to,
* state updates are done by the caller. Returns non-zero if an
* error occurred which prevented the send.
*/
-int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
unsigned int cur_mss;
- int err;
/* Inconslusive MTU probe */
if (icsk->icsk_mtup.probe_size) {
@@ -2383,11 +2386,17 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
if (unlikely(NET_IP_ALIGN && ((unsigned long)skb->data & 3))) {
struct sk_buff *nskb = __pskb_copy(skb, MAX_TCP_HEADER,
GFP_ATOMIC);
- err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
- -ENOBUFS;
+ return nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) :
+ -ENOBUFS;
} else {
- err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
+ return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC);
}
+}
+
+int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ int err = __tcp_retransmit_skb(sk, skb);
if (err == 0) {
/* Update global TCP statistics. */
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 05c5ab8d983c..3be0ac2c1920 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -279,19 +279,8 @@ static void __exit xfrm4_policy_fini(void)
xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo);
}
-void __init xfrm4_init(int rt_max_size)
+void __init xfrm4_init(void)
{
- /*
- * Select a default value for the gc_thresh based on the main route
- * table hash size. It seems to me the worst case scenario is when
- * we have ipsec operating in transport mode, in which we create a
- * dst_entry per socket. The xfrm gc algorithm starts trying to remove
- * entries at gc_thresh, and prevents new allocations as 2*gc_thresh
- * so lets set an initial xfrm gc_thresh value at the rt_max_size/2.
- * That will let us store an ipsec connection per route table entry,
- * and start cleaning when were 1/2 full
- */
- xfrm4_dst_ops.gc_thresh = rt_max_size/2;
dst_entries_init(&xfrm4_dst_ops);
xfrm4_state_init();
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index c4f934176cab..30647857a375 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -252,6 +252,7 @@ struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu)
return NULL;
dst->ops->update_pmtu(dst, sk, NULL, mtu);
- return inet6_csk_route_socket(sk, &fl6);
+ dst = inet6_csk_route_socket(sk, &fl6);
+ return IS_ERR(dst) ? NULL : dst;
}
EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index ba6d13d1f1e1..e02faed6d17e 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -827,6 +827,7 @@ pref_skip_coa:
if (val < 0 || val > 255)
goto e_inval;
np->min_hopcount = val;
+ retv = 0;
break;
case IPV6_DONTFRAG:
np->dontfrag = valbool;
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 1002e3396f72..ae43c62f9045 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -441,6 +441,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0);
if (lsap == NULL) {
IRDA_DEBUG(0, "%s: unable to allocate LSAP!!\n", __func__);
+ __irttp_close_tsap(self);
return NULL;
}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 05f3a313db88..7371f676cf41 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2594,6 +2594,9 @@ static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
else
local->probe_req_reg--;
+ if (!local->open_count)
+ break;
+
ieee80211_queue_work(&local->hw, &local->reconfig_filter);
break;
default:
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index bf87c70ac6c5..c21e33d1abd0 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -1151,10 +1151,6 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
mutex_lock(&sdata->u.ibss.mtx);
- sdata->u.ibss.state = IEEE80211_IBSS_MLME_SEARCH;
- memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
- sdata->u.ibss.ssid_len = 0;
-
active_ibss = ieee80211_sta_active_ibss(sdata);
if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
@@ -1175,6 +1171,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
}
}
+ ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
+ memset(ifibss->bssid, 0, ETH_ALEN);
+ ifibss->ssid_len = 0;
+
sta_info_flush(sdata->local, sdata);
spin_lock_bh(&ifibss->incomplete_lock);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8c804550465b..156e5835e37f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1314,6 +1314,8 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
struct net_device *dev);
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev);
+void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
+ struct sk_buff_head *skbs);
/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index c80c4490351c..f57f597972f8 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -871,8 +871,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
local->hw.wiphy->cipher_suites,
sizeof(u32) * local->hw.wiphy->n_cipher_suites,
GFP_KERNEL);
- if (!suites)
- return -ENOMEM;
+ if (!suites) {
+ result = -ENOMEM;
+ goto fail_wiphy_register;
+ }
for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {
u32 suite = local->hw.wiphy->cipher_suites[r];
if (suite == WLAN_CIPHER_SUITE_WEP40 ||
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 83608ac16780..2c84185dfdb0 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -458,8 +458,6 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
list_move_tail(&roc->list, &tmp_list);
roc->abort = true;
}
-
- ieee80211_start_next_roc(local);
mutex_unlock(&local->mtx);
list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index c4cdbde24fd3..43e60b5a7546 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -917,7 +917,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
struct cfg80211_sched_scan_request *req)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_sched_scan_ies sched_scan_ies;
+ struct ieee80211_sched_scan_ies sched_scan_ies = {};
int ret, i;
mutex_lock(&local->mtx);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 0a4e4c04db89..d2eb64e12353 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -117,8 +117,8 @@ static void free_sta_work(struct work_struct *wk)
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
local->total_ps_buffered -= skb_queue_len(&sta->ps_tx_buf[ac]);
- __skb_queue_purge(&sta->ps_tx_buf[ac]);
- __skb_queue_purge(&sta->tx_filtered[ac]);
+ ieee80211_purge_tx_queue(&local->hw, &sta->ps_tx_buf[ac]);
+ ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
}
#ifdef CONFIG_MAC80211_MESH
@@ -141,7 +141,7 @@ static void free_sta_work(struct work_struct *wk)
tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
if (!tid_tx)
continue;
- __skb_queue_purge(&tid_tx->pending);
+ ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx);
}
@@ -961,6 +961,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
int filtered = 0, buffered = 0, ac;
+ unsigned long flags;
clear_sta_flag(sta, WLAN_STA_SP);
@@ -976,12 +977,16 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
int count = skb_queue_len(&pending), tmp;
+ spin_lock_irqsave(&sta->tx_filtered[ac].lock, flags);
skb_queue_splice_tail_init(&sta->tx_filtered[ac], &pending);
+ spin_unlock_irqrestore(&sta->tx_filtered[ac].lock, flags);
tmp = skb_queue_len(&pending);
filtered += tmp - count;
count = tmp;
+ spin_lock_irqsave(&sta->ps_tx_buf[ac].lock, flags);
skb_queue_splice_tail_init(&sta->ps_tx_buf[ac], &pending);
+ spin_unlock_irqrestore(&sta->ps_tx_buf[ac].lock, flags);
tmp = skb_queue_len(&pending);
buffered += tmp - count;
}
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3af0cc4130f1..101eb88a2b78 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -668,3 +668,12 @@ void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL(ieee80211_free_txskb);
+
+void ieee80211_purge_tx_queue(struct ieee80211_hw *hw,
+ struct sk_buff_head *skbs)
+{
+ struct sk_buff *skb;
+
+ while ((skb = __skb_dequeue(skbs)))
+ ieee80211_free_txskb(hw, skb);
+}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c9bf83f36657..b858ebe41fda 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1358,7 +1358,7 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
if (tx->skb)
ieee80211_free_txskb(&tx->local->hw, tx->skb);
else
- __skb_queue_purge(&tx->skbs);
+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
return -1;
} else if (unlikely(res == TX_QUEUED)) {
I802_DEBUG_INC(tx->local->tx_handlers_queued);
@@ -2120,10 +2120,13 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
*/
void ieee80211_clear_tx_pending(struct ieee80211_local *local)
{
+ struct sk_buff *skb;
int i;
- for (i = 0; i < local->hw.queues; i++)
- skb_queue_purge(&local->pending[i]);
+ for (i = 0; i < local->hw.queues; i++) {
+ while ((skb = skb_dequeue(&local->pending[i])) != NULL)
+ ieee80211_free_txskb(&local->hw, skb);
+ }
}
/*
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 239391807ca9..0151ae33c4cd 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1491,6 +1491,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->vif.type != NL80211_IFTYPE_STATION)
continue;
+ if (!sdata->u.mgd.associated)
+ continue;
ieee80211_send_nullfunc(local, sdata, 0);
}
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index ec3dba5dcd62..5c0b78528e55 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -173,6 +173,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
return adtfn(set, &nip, timeout, flags);
}
+ ip_to = ip;
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -185,8 +186,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr);
- } else
- ip_to = ip;
+ }
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 0171f7502fa5..6283351f4eeb 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -162,7 +162,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem data = { };
- u32 ip, ip_to = 0, p = 0, port, port_to;
+ u32 ip, ip_to, p = 0, port, port_to;
u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -210,7 +210,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
return ip_set_eexist(ret, flags) ? 0 : ret;
}
- ip = ntohl(data.ip);
+ ip_to = ip = ntohl(data.ip);
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -223,8 +223,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr);
- } else
- ip_to = ip;
+ }
port_to = port = ntohs(data.port);
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 6344ef551ec8..6a21271c8d5a 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -166,7 +166,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem data = { };
- u32 ip, ip_to = 0, p = 0, port, port_to;
+ u32 ip, ip_to, p = 0, port, port_to;
u32 timeout = h->timeout;
bool with_ports = false;
int ret;
@@ -218,7 +218,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
return ip_set_eexist(ret, flags) ? 0 : ret;
}
- ip = ntohl(data.ip);
+ ip_to = ip = ntohl(data.ip);
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -231,8 +231,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr);
- } else
- ip_to = ip;
+ }
port_to = port = ntohs(data.port);
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index cb71f9a774e7..2d5cd4ee30eb 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -215,8 +215,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK - 1 };
- u32 ip, ip_to = 0, p = 0, port, port_to;
- u32 ip2_from = 0, ip2_to, ip2_last, ip2;
+ 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;
@@ -286,6 +286,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
return ip_set_eexist(ret, flags) ? 0 : ret;
}
+ ip_to = ip;
if (tb[IPSET_ATTR_IP_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
if (ret)
@@ -306,6 +307,8 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (port > port_to)
swap(port, port_to);
}
+
+ ip2_to = ip2_from;
if (tb[IPSET_ATTR_IP2_TO]) {
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
if (ret)
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index b9a63381e349..45a101439bc5 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -793,7 +793,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
[IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING,
- .len = IPSET_MAXNAMELEN - 1 },
+ .len = IFNAMSIZ - 1 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index 8847b4d8be06..701c88a20fea 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -41,7 +41,8 @@ MODULE_DESCRIPTION("cttimeout: Extended Netfilter Connection Tracking timeout tu
static LIST_HEAD(cttimeout_list);
static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
- [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING },
+ [CTA_TIMEOUT_NAME] = { .type = NLA_NUL_STRING,
+ .len = CTNL_TIMEOUT_NAME_MAX - 1},
[CTA_TIMEOUT_L3PROTO] = { .type = NLA_U16 },
[CTA_TIMEOUT_L4PROTO] = { .type = NLA_U8 },
[CTA_TIMEOUT_DATA] = { .type = NLA_NESTED },
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index cc10d073c338..9e8f4b2801f6 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -1210,7 +1210,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
local->remote_miu = LLCP_DEFAULT_MIU;
local->remote_lto = LLCP_DEFAULT_LTO;
- list_add(&llcp_devices, &local->list);
+ list_add(&local->list, &llcp_devices);
return 0;
}
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 98c70630ad06..733cbf49ed1f 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -702,15 +702,11 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
/* We only match on the lower 8 bits of the opcode. */
if (ntohs(arp->ar_op) <= 0xff)
key->ip.proto = ntohs(arp->ar_op);
-
- if (key->ip.proto == ARPOP_REQUEST
- || key->ip.proto == ARPOP_REPLY) {
- memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
- memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
- memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
- memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
- key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
- }
+ memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
+ memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
+ memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
+ memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
+ key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
}
} else if (key->eth.type == htons(ETH_P_IPV6)) {
int nh_len; /* IPv6 Header + Extensions */
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index 3c1e58ba714b..a9033481fa5e 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -158,7 +158,7 @@ static int netdev_send(struct vport *vport, struct sk_buff *skb)
if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {
net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n",
- ovs_dp_name(vport->dp),
+ netdev_vport->dev->name,
packet_length(skb), mtu);
goto error;
}
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 7c2df9c33df3..69ce21e3716f 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -183,7 +183,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
msg = sctp_datamsg_new(GFP_KERNEL);
if (!msg)
- return NULL;
+ return ERR_PTR(-ENOMEM);
/* Note: Calculate this outside of the loop, so that all fragments
* have the same expiration.
@@ -280,11 +280,14 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
- if (!chunk)
+ if (!chunk) {
+ err = -ENOMEM;
goto errout;
+ }
+
err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov);
if (err < 0)
- goto errout;
+ goto errout_chunk_free;
offset += len;
@@ -315,8 +318,10 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
- if (!chunk)
+ if (!chunk) {
+ err = -ENOMEM;
goto errout;
+ }
err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov);
@@ -324,7 +329,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
- (__u8 *)chunk->skb->data);
if (err < 0)
- goto errout;
+ goto errout_chunk_free;
sctp_datamsg_assign(msg, chunk);
list_add_tail(&chunk->frag_list, &msg->chunks);
@@ -332,6 +337,9 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
return msg;
+errout_chunk_free:
+ sctp_chunk_free(chunk);
+
errout:
list_for_each_safe(pos, temp, &msg->chunks) {
list_del_init(pos);
@@ -339,7 +347,7 @@ errout:
sctp_chunk_free(chunk);
}
sctp_datamsg_put(msg);
- return NULL;
+ return ERR_PTR(err);
}
/* Check whether this message has expired. */
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index c3bea269faf4..9966e7b16451 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -102,7 +102,7 @@ static const struct file_operations sctp_snmp_seq_fops = {
.open = sctp_snmp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = single_release,
+ .release = single_release_net,
};
/* Set up the proc fs entry for 'snmp' object. */
@@ -251,7 +251,7 @@ static const struct file_operations sctp_eps_seq_fops = {
.open = sctp_eps_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_net,
};
/* Set up the proc fs entry for 'eps' object. */
@@ -372,7 +372,7 @@ static const struct file_operations sctp_assocs_seq_fops = {
.open = sctp_assocs_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_net,
};
/* Set up the proc fs entry for 'assocs' object. */
@@ -517,7 +517,7 @@ static const struct file_operations sctp_remaddr_seq_fops = {
.open = sctp_remaddr_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_net,
};
int __net_init sctp_remaddr_proc_init(struct net *net)
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a60d1f8b41c5..406d957d08fb 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1915,8 +1915,8 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* Break the message into multiple chunks of maximum size. */
datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len);
- if (!datamsg) {
- err = -ENOMEM;
+ if (IS_ERR(datamsg)) {
+ err = PTR_ERR(datamsg);
goto out_free;
}
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 953c21e4af97..206cf5238fd3 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -331,7 +331,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
* 1/8, rto_alpha would be expressed as 3.
*/
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta)
- + ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta);
+ + (((__u32)abs64((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta);
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha)
+ (rtt >> net->sctp.rto_alpha);
} else {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bcc7d7ee5a51..b75756b05af7 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -141,9 +141,8 @@ static const struct ieee80211_regdomain world_regdom = {
.reg_rules = {
/* IEEE 802.11b/g, channels 1..11 */
REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
- /* IEEE 802.11b/g, channels 12..13. No HT40
- * channel fits here. */
- REG_RULE(2467-10, 2472+10, 20, 6, 20,
+ /* IEEE 802.11b/g, channels 12..13. */
+ REG_RULE(2467-10, 2472+10, 40, 6, 20,
NL80211_RRF_PASSIVE_SCAN |
NL80211_RRF_NO_IBSS),
/* IEEE 802.11 channel 14 - Only JP enables
diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl
index 239d22d4207b..6c353ae8a451 100644
--- a/scripts/headers_install.pl
+++ b/scripts/headers_install.pl
@@ -42,6 +42,9 @@ foreach my $filename (@files) {
$line =~ s/(^|\s)(inline)\b/$1__$2__/g;
$line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g;
$line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g;
+ $line =~ s/#ifndef _UAPI/#ifndef /;
+ $line =~ s/#define _UAPI/#define /;
+ $line =~ s!#endif /[*] _UAPI!#endif /* !;
printf {$out} "%s", $line;
}
close $out;
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index bd2e09895553..cdd48600e02a 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -12,7 +12,7 @@ extern "C" {
#include <assert.h>
#include <stdio.h>
-#include <sys/queue.h>
+#include "list.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
@@ -175,12 +175,11 @@ struct menu {
#define MENU_ROOT 0x0002
struct jump_key {
- CIRCLEQ_ENTRY(jump_key) entries;
+ struct list_head entries;
size_t offset;
struct menu *target;
int index;
};
-CIRCLEQ_HEAD(jk_head, jump_key);
#define JUMP_NB 9
diff --git a/scripts/kconfig/list.h b/scripts/kconfig/list.h
new file mode 100644
index 000000000000..0ae730be5f49
--- /dev/null
+++ b/scripts/kconfig/list.h
@@ -0,0 +1,91 @@
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Copied from include/linux/...
+ */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *_new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = _new;
+ _new->next = next;
+ _new->prev = prev;
+ prev->next = _new;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+ __list_add(_new, head->prev, head);
+}
+
+#endif
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index 1d1c08537f1e..ef1a7381f956 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -21,9 +21,9 @@ P(menu_get_root_menu,struct menu *,(struct menu *menu));
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
P(menu_has_help,bool,(struct menu *menu));
P(menu_get_help,const char *,(struct menu *menu));
-P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct jk_head
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head
*head));
-P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct jk_head
+P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head
*head));
P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 48f67448af7b..53975cf87608 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -312,7 +312,7 @@ static void set_config_filename(const char *config_filename)
struct search_data {
- struct jk_head *head;
+ struct list_head *head;
struct menu **targets;
int *keys;
};
@@ -323,7 +323,7 @@ static void update_text(char *buf, size_t start, size_t end, void *_data)
struct jump_key *pos;
int k = 0;
- CIRCLEQ_FOREACH(pos, data->head, entries) {
+ list_for_each_entry(pos, data->head, entries) {
if (pos->offset >= start && pos->offset < end) {
char header[4];
@@ -375,7 +375,7 @@ again:
sym_arr = sym_re_search(dialog_input);
do {
- struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head);
+ LIST_HEAD(head);
struct menu *targets[JUMP_NB];
int keys[JUMP_NB + 1], i;
struct search_data data = {
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index a3cade659f89..e98a05c8e508 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -508,7 +508,7 @@ const char *menu_get_help(struct menu *menu)
}
static void get_prompt_str(struct gstr *r, struct property *prop,
- struct jk_head *head)
+ struct list_head *head)
{
int i, j;
struct menu *submenu[8], *menu, *location = NULL;
@@ -544,12 +544,13 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
} else
jump->target = location;
- if (CIRCLEQ_EMPTY(head))
+ if (list_empty(head))
jump->index = 0;
else
- jump->index = CIRCLEQ_LAST(head)->index + 1;
+ jump->index = list_entry(head->prev, struct jump_key,
+ entries)->index + 1;
- CIRCLEQ_INSERT_TAIL(head, jump, entries);
+ list_add_tail(&jump->entries, head);
}
if (i > 0) {
@@ -573,7 +574,8 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
/*
* head is optional and may be NULL
*/
-void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head)
+void get_symbol_str(struct gstr *r, struct symbol *sym,
+ struct list_head *head)
{
bool hit;
struct property *prop;
@@ -612,7 +614,7 @@ void get_symbol_str(struct gstr *r, struct symbol *sym, struct jk_head *head)
str_append(r, "\n\n");
}
-struct gstr get_relations_str(struct symbol **sym_arr, struct jk_head *head)
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
{
struct symbol *sym;
struct gstr res = str_new();
diff --git a/scripts/sign-file b/scripts/sign-file
index 87ca59d36e7e..974a20b661b7 100755
--- a/scripts/sign-file
+++ b/scripts/sign-file
@@ -156,12 +156,12 @@ sub asn1_extract($$@)
if ($l == 0x1) {
$len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
- } elsif ($l = 0x2) {
+ } elsif ($l == 0x2) {
$len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
- } elsif ($l = 0x3) {
+ } elsif ($l == 0x3) {
$len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
$len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
- } elsif ($l = 0x4) {
+ } elsif ($l == 0x4) {
$len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
} else {
die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 842c254396db..b08d20c66c2e 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -164,8 +164,8 @@ static void dev_exception_clean(struct dev_cgroup *dev_cgroup)
struct dev_exception_item *ex, *tmp;
list_for_each_entry_safe(ex, tmp, &dev_cgroup->exceptions, list) {
- list_del(&ex->list);
- kfree(ex);
+ list_del_rcu(&ex->list);
+ kfree_rcu(ex, rcu);
}
}
@@ -298,7 +298,7 @@ static int may_access(struct dev_cgroup *dev_cgroup,
struct dev_exception_item *ex;
bool match = false;
- list_for_each_entry(ex, &dev_cgroup->exceptions, list) {
+ list_for_each_entry_rcu(ex, &dev_cgroup->exceptions, list) {
if ((refex->type & DEV_BLOCK) && !(ex->type & DEV_BLOCK))
continue;
if ((refex->type & DEV_CHAR) && !(ex->type & DEV_CHAR))
@@ -352,6 +352,8 @@ static int parent_has_perm(struct dev_cgroup *childcg,
*/
static inline int may_allow_all(struct dev_cgroup *parent)
{
+ if (!parent)
+ return 1;
return parent->behavior == DEVCG_DEFAULT_ALLOW;
}
@@ -376,11 +378,14 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
int count, rc;
struct dev_exception_item ex;
struct cgroup *p = devcgroup->css.cgroup;
- struct dev_cgroup *parent = cgroup_to_devcgroup(p->parent);
+ struct dev_cgroup *parent = NULL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (p->parent)
+ parent = cgroup_to_devcgroup(p->parent);
+
memset(&ex, 0, sizeof(ex));
b = buffer;
@@ -391,11 +396,14 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup,
if (!may_allow_all(parent))
return -EPERM;
dev_exception_clean(devcgroup);
+ devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
+ if (!parent)
+ break;
+
rc = dev_exceptions_copy(&devcgroup->exceptions,
&parent->exceptions);
if (rc)
return rc;
- devcgroup->behavior = DEVCG_DEFAULT_ALLOW;
break;
case DEVCG_DENY:
dev_exception_clean(devcgroup);
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 28f911cdd7c7..c5454c0477c3 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -174,7 +174,8 @@ static void sel_netnode_insert(struct sel_netnode *node)
if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
struct sel_netnode *tail;
tail = list_entry(
- rcu_dereference(sel_netnode_hash[idx].list.prev),
+ rcu_dereference_protected(sel_netnode_hash[idx].list.prev,
+ lockdep_is_held(&sel_netnode_lock)),
struct sel_netnode, list);
list_del_rcu(&tail->list);
kfree_rcu(tail, rcu);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index 50169bcfd903..7266020c16cb 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2581,9 +2581,14 @@ static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea)
struct es1968 *chip = tea->private_data;
unsigned long io = chip->io_port + GPIO_DATA;
u16 val = inw(io);
-
- return (val & STR_DATA) ? TEA575X_DATA : 0 |
- (val & STR_MOST) ? TEA575X_MOST : 0;
+ u8 ret;
+
+ ret = 0;
+ if (val & STR_DATA)
+ ret |= TEA575X_DATA;
+ if (val & STR_MOST)
+ ret |= TEA575X_MOST;
+ return ret;
}
static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output)
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index cc2e91d15538..c5806f89be1e 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -767,9 +767,14 @@ static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea)
struct fm801 *chip = tea->private_data;
unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL));
struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip);
-
- return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 |
- (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0;
+ u8 ret;
+
+ ret = 0;
+ if (reg & FM801_GPIO_GP(gpio.data))
+ ret |= TEA575X_DATA;
+ if (reg & FM801_GPIO_GP(gpio.most))
+ ret |= TEA575X_MOST;
+ return ret;
}
static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output)
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 70d4848b5cd0..d010de12335e 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -95,6 +95,7 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset);
#ifdef CONFIG_PM
+#define codec_in_pm(codec) ((codec)->in_pm)
static void hda_power_work(struct work_struct *work);
static void hda_keep_power_on(struct hda_codec *codec);
#define hda_codec_is_power_on(codec) ((codec)->power_on)
@@ -104,6 +105,7 @@ static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up)
bus->ops.pm_notify(bus, power_up);
}
#else
+#define codec_in_pm(codec) 0
static inline void hda_keep_power_on(struct hda_codec *codec) {}
#define hda_codec_is_power_on(codec) 1
#define hda_call_pm_notify(bus, state) {}
@@ -228,7 +230,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
}
mutex_unlock(&bus->cmd_mutex);
snd_hda_power_down(codec);
- if (res && *res == -1 && bus->rirb_error) {
+ if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) {
if (bus->response_reset) {
snd_printd("hda_codec: resetting BUS due to "
"fatal communication error\n");
@@ -238,7 +240,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd,
goto again;
}
/* clear reset-flag when the communication gets recovered */
- if (!err)
+ if (!err || codec_in_pm(codec))
bus->response_reset = 0;
return err;
}
@@ -3616,6 +3618,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
{
unsigned int state;
+ codec->in_pm = 1;
+
if (codec->patch_ops.suspend)
codec->patch_ops.suspend(codec);
hda_cleanup_all_streams(codec);
@@ -3630,6 +3634,7 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
codec->power_transition = 0;
codec->power_jiffies = jiffies;
spin_unlock(&codec->power_lock);
+ codec->in_pm = 0;
return state;
}
@@ -3638,6 +3643,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq)
*/
static void hda_call_codec_resume(struct hda_codec *codec)
{
+ codec->in_pm = 1;
+
/* set as if powered on for avoiding re-entering the resume
* in the resume / power-save sequence
*/
@@ -3656,6 +3663,8 @@ static void hda_call_codec_resume(struct hda_codec *codec)
snd_hda_codec_resume_cache(codec);
}
snd_hda_jack_report_sync(codec);
+
+ codec->in_pm = 0;
snd_hda_power_down(codec); /* flag down before returning */
}
#endif /* CONFIG_PM */
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 507fe8a917b6..4f4e545c0f4b 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -869,6 +869,7 @@ struct hda_codec {
unsigned int power_on :1; /* current (global) power-state */
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
unsigned int pm_down_notified:1; /* PM notified to controller */
+ unsigned int in_pm:1; /* suspend/resume being performed */
int power_transition; /* power-state in transition */
int power_count; /* current (global) power refcount */
struct delayed_work power_work; /* delayed task for powerdown */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index cd2dbaf1be78..f9d870e554d9 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -556,6 +556,12 @@ enum {
#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
+#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */
+
+/* quirks for Intel PCH */
+#define AZX_DCAPS_INTEL_PCH \
+ (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \
+ AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME)
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
@@ -2433,6 +2439,9 @@ static void azx_power_notify(struct hda_bus *bus, bool power_up)
{
struct azx *chip = bus->private_data;
+ if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
+ return;
+
if (power_up)
pm_runtime_get_sync(&chip->pci->dev);
else
@@ -2548,7 +2557,8 @@ static int azx_runtime_suspend(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip = card->private_data;
- if (!power_save_controller)
+ if (!power_save_controller ||
+ !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
return -EAGAIN;
azx_stop_chip(chip);
@@ -3429,39 +3439,30 @@ static void __devexit azx_remove(struct pci_dev *pci)
static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
/* CPT */
{ PCI_DEVICE(0x8086, 0x1c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* PBG */
{ PCI_DEVICE(0x8086, 0x1d20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE},
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Panther Point */
{ PCI_DEVICE(0x8086, 0x1e20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point */
{ PCI_DEVICE(0x8086, 0x8c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c20),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Lynx Point-LP */
{ PCI_DEVICE(0x8086, 0x9c21),
- .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0c0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
{ PCI_DEVICE(0x8086, 0x0d0c),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
/* 5 Series/3400 */
{ PCI_DEVICE(0x8086, 0x3b56),
- .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
- AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY },
+ .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH },
/* SCH */
{ PCI_DEVICE(0x8086, 0x811b),
.driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index d5f3a26d608d..3bcb67172358 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -466,6 +466,7 @@ static int parse_output(struct hda_codec *codec)
memcpy(cfg->speaker_pins, cfg->line_out_pins,
sizeof(cfg->speaker_pins));
cfg->line_outs = 0;
+ memset(cfg->line_out_pins, 0, sizeof(cfg->line_out_pins));
}
return 0;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index c0ce3b1f04b4..ad68d223f8af 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5407,6 +5407,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO),
+ SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF),
@@ -7064,6 +7065,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 },
{ .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 },
{ .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 },
+ { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 },
{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
.patch = patch_alc861 },
{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index c03b65af3059..054967d8bac2 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -268,7 +268,7 @@ EXPORT_SYMBOL_GPL(arizona_out_ev);
static unsigned int arizona_sysclk_48k_rates[] = {
6144000,
12288000,
- 22579200,
+ 24576000,
49152000,
73728000,
98304000,
@@ -278,7 +278,7 @@ static unsigned int arizona_sysclk_48k_rates[] = {
static unsigned int arizona_sysclk_44k1_rates[] = {
5644800,
11289600,
- 24576000,
+ 22579200,
45158400,
67737600,
90316800,
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index f994af34f552..e3f0a7f3131e 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -485,7 +485,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
gpio_nreset = cs4271plat->gpio_nreset;
if (gpio_nreset >= 0)
- if (gpio_request(gpio_nreset, "CS4271 Reset"))
+ if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset"))
gpio_nreset = -EINVAL;
if (gpio_nreset >= 0) {
/* Reset codec */
@@ -535,15 +535,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
static int cs4271_remove(struct snd_soc_codec *codec)
{
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
- int gpio_nreset;
- gpio_nreset = cs4271->gpio_nreset;
-
- if (gpio_is_valid(gpio_nreset)) {
+ if (gpio_is_valid(cs4271->gpio_nreset))
/* Set codec to the reset state */
- gpio_set_value(gpio_nreset, 0);
- gpio_free(gpio_nreset);
- }
+ gpio_set_value(cs4271->gpio_nreset, 0);
return 0;
};
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
index 4d8db3685e96..97a81051e88d 100644
--- a/sound/soc/codecs/cs42l52.c
+++ b/sound/soc/codecs/cs42l52.c
@@ -773,7 +773,6 @@ static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
u8 iface = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -822,7 +821,7 @@ static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
case SND_SOC_DAIFMT_NB_IF:
break;
default:
- ret = -EINVAL;
+ return -EINVAL;
}
cs42l52->config.format = iface;
snd_soc_write(codec, CS42L52_IFACE_CTL1, cs42l52->config.format);
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index 1722b586bdba..7394e73fa43c 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -42,6 +42,556 @@ static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+static const struct reg_default wm5102_sysclk_reva_patch[] = {
+ { 0x3000, 0x2225 },
+ { 0x3001, 0x3a03 },
+ { 0x3002, 0x0225 },
+ { 0x3003, 0x0801 },
+ { 0x3004, 0x6249 },
+ { 0x3005, 0x0c04 },
+ { 0x3006, 0x0225 },
+ { 0x3007, 0x5901 },
+ { 0x3008, 0xe249 },
+ { 0x3009, 0x030d },
+ { 0x300a, 0x0249 },
+ { 0x300b, 0x2c01 },
+ { 0x300c, 0xe249 },
+ { 0x300d, 0x4342 },
+ { 0x300e, 0xe249 },
+ { 0x300f, 0x73c0 },
+ { 0x3010, 0x4249 },
+ { 0x3011, 0x0c00 },
+ { 0x3012, 0x0225 },
+ { 0x3013, 0x1f01 },
+ { 0x3014, 0x0225 },
+ { 0x3015, 0x1e01 },
+ { 0x3016, 0x0225 },
+ { 0x3017, 0xfa00 },
+ { 0x3018, 0x0000 },
+ { 0x3019, 0xf000 },
+ { 0x301a, 0x0000 },
+ { 0x301b, 0xf000 },
+ { 0x301c, 0x0000 },
+ { 0x301d, 0xf000 },
+ { 0x301e, 0x0000 },
+ { 0x301f, 0xf000 },
+ { 0x3020, 0x0000 },
+ { 0x3021, 0xf000 },
+ { 0x3022, 0x0000 },
+ { 0x3023, 0xf000 },
+ { 0x3024, 0x0000 },
+ { 0x3025, 0xf000 },
+ { 0x3026, 0x0000 },
+ { 0x3027, 0xf000 },
+ { 0x3028, 0x0000 },
+ { 0x3029, 0xf000 },
+ { 0x302a, 0x0000 },
+ { 0x302b, 0xf000 },
+ { 0x302c, 0x0000 },
+ { 0x302d, 0xf000 },
+ { 0x302e, 0x0000 },
+ { 0x302f, 0xf000 },
+ { 0x3030, 0x0225 },
+ { 0x3031, 0x1a01 },
+ { 0x3032, 0x0225 },
+ { 0x3033, 0x1e00 },
+ { 0x3034, 0x0225 },
+ { 0x3035, 0x1f00 },
+ { 0x3036, 0x6225 },
+ { 0x3037, 0xf800 },
+ { 0x3038, 0x0000 },
+ { 0x3039, 0xf000 },
+ { 0x303a, 0x0000 },
+ { 0x303b, 0xf000 },
+ { 0x303c, 0x0000 },
+ { 0x303d, 0xf000 },
+ { 0x303e, 0x0000 },
+ { 0x303f, 0xf000 },
+ { 0x3040, 0x2226 },
+ { 0x3041, 0x3a03 },
+ { 0x3042, 0x0226 },
+ { 0x3043, 0x0801 },
+ { 0x3044, 0x6249 },
+ { 0x3045, 0x0c06 },
+ { 0x3046, 0x0226 },
+ { 0x3047, 0x5901 },
+ { 0x3048, 0xe249 },
+ { 0x3049, 0x030d },
+ { 0x304a, 0x0249 },
+ { 0x304b, 0x2c01 },
+ { 0x304c, 0xe249 },
+ { 0x304d, 0x4342 },
+ { 0x304e, 0xe249 },
+ { 0x304f, 0x73c0 },
+ { 0x3050, 0x4249 },
+ { 0x3051, 0x0c00 },
+ { 0x3052, 0x0226 },
+ { 0x3053, 0x1f01 },
+ { 0x3054, 0x0226 },
+ { 0x3055, 0x1e01 },
+ { 0x3056, 0x0226 },
+ { 0x3057, 0xfa00 },
+ { 0x3058, 0x0000 },
+ { 0x3059, 0xf000 },
+ { 0x305a, 0x0000 },
+ { 0x305b, 0xf000 },
+ { 0x305c, 0x0000 },
+ { 0x305d, 0xf000 },
+ { 0x305e, 0x0000 },
+ { 0x305f, 0xf000 },
+ { 0x3060, 0x0000 },
+ { 0x3061, 0xf000 },
+ { 0x3062, 0x0000 },
+ { 0x3063, 0xf000 },
+ { 0x3064, 0x0000 },
+ { 0x3065, 0xf000 },
+ { 0x3066, 0x0000 },
+ { 0x3067, 0xf000 },
+ { 0x3068, 0x0000 },
+ { 0x3069, 0xf000 },
+ { 0x306a, 0x0000 },
+ { 0x306b, 0xf000 },
+ { 0x306c, 0x0000 },
+ { 0x306d, 0xf000 },
+ { 0x306e, 0x0000 },
+ { 0x306f, 0xf000 },
+ { 0x3070, 0x0226 },
+ { 0x3071, 0x1a01 },
+ { 0x3072, 0x0226 },
+ { 0x3073, 0x1e00 },
+ { 0x3074, 0x0226 },
+ { 0x3075, 0x1f00 },
+ { 0x3076, 0x6226 },
+ { 0x3077, 0xf800 },
+ { 0x3078, 0x0000 },
+ { 0x3079, 0xf000 },
+ { 0x307a, 0x0000 },
+ { 0x307b, 0xf000 },
+ { 0x307c, 0x0000 },
+ { 0x307d, 0xf000 },
+ { 0x307e, 0x0000 },
+ { 0x307f, 0xf000 },
+ { 0x3080, 0x2227 },
+ { 0x3081, 0x3a03 },
+ { 0x3082, 0x0227 },
+ { 0x3083, 0x0801 },
+ { 0x3084, 0x6255 },
+ { 0x3085, 0x0c04 },
+ { 0x3086, 0x0227 },
+ { 0x3087, 0x5901 },
+ { 0x3088, 0xe255 },
+ { 0x3089, 0x030d },
+ { 0x308a, 0x0255 },
+ { 0x308b, 0x2c01 },
+ { 0x308c, 0xe255 },
+ { 0x308d, 0x4342 },
+ { 0x308e, 0xe255 },
+ { 0x308f, 0x73c0 },
+ { 0x3090, 0x4255 },
+ { 0x3091, 0x0c00 },
+ { 0x3092, 0x0227 },
+ { 0x3093, 0x1f01 },
+ { 0x3094, 0x0227 },
+ { 0x3095, 0x1e01 },
+ { 0x3096, 0x0227 },
+ { 0x3097, 0xfa00 },
+ { 0x3098, 0x0000 },
+ { 0x3099, 0xf000 },
+ { 0x309a, 0x0000 },
+ { 0x309b, 0xf000 },
+ { 0x309c, 0x0000 },
+ { 0x309d, 0xf000 },
+ { 0x309e, 0x0000 },
+ { 0x309f, 0xf000 },
+ { 0x30a0, 0x0000 },
+ { 0x30a1, 0xf000 },
+ { 0x30a2, 0x0000 },
+ { 0x30a3, 0xf000 },
+ { 0x30a4, 0x0000 },
+ { 0x30a5, 0xf000 },
+ { 0x30a6, 0x0000 },
+ { 0x30a7, 0xf000 },
+ { 0x30a8, 0x0000 },
+ { 0x30a9, 0xf000 },
+ { 0x30aa, 0x0000 },
+ { 0x30ab, 0xf000 },
+ { 0x30ac, 0x0000 },
+ { 0x30ad, 0xf000 },
+ { 0x30ae, 0x0000 },
+ { 0x30af, 0xf000 },
+ { 0x30b0, 0x0227 },
+ { 0x30b1, 0x1a01 },
+ { 0x30b2, 0x0227 },
+ { 0x30b3, 0x1e00 },
+ { 0x30b4, 0x0227 },
+ { 0x30b5, 0x1f00 },
+ { 0x30b6, 0x6227 },
+ { 0x30b7, 0xf800 },
+ { 0x30b8, 0x0000 },
+ { 0x30b9, 0xf000 },
+ { 0x30ba, 0x0000 },
+ { 0x30bb, 0xf000 },
+ { 0x30bc, 0x0000 },
+ { 0x30bd, 0xf000 },
+ { 0x30be, 0x0000 },
+ { 0x30bf, 0xf000 },
+ { 0x30c0, 0x2228 },
+ { 0x30c1, 0x3a03 },
+ { 0x30c2, 0x0228 },
+ { 0x30c3, 0x0801 },
+ { 0x30c4, 0x6255 },
+ { 0x30c5, 0x0c06 },
+ { 0x30c6, 0x0228 },
+ { 0x30c7, 0x5901 },
+ { 0x30c8, 0xe255 },
+ { 0x30c9, 0x030d },
+ { 0x30ca, 0x0255 },
+ { 0x30cb, 0x2c01 },
+ { 0x30cc, 0xe255 },
+ { 0x30cd, 0x4342 },
+ { 0x30ce, 0xe255 },
+ { 0x30cf, 0x73c0 },
+ { 0x30d0, 0x4255 },
+ { 0x30d1, 0x0c00 },
+ { 0x30d2, 0x0228 },
+ { 0x30d3, 0x1f01 },
+ { 0x30d4, 0x0228 },
+ { 0x30d5, 0x1e01 },
+ { 0x30d6, 0x0228 },
+ { 0x30d7, 0xfa00 },
+ { 0x30d8, 0x0000 },
+ { 0x30d9, 0xf000 },
+ { 0x30da, 0x0000 },
+ { 0x30db, 0xf000 },
+ { 0x30dc, 0x0000 },
+ { 0x30dd, 0xf000 },
+ { 0x30de, 0x0000 },
+ { 0x30df, 0xf000 },
+ { 0x30e0, 0x0000 },
+ { 0x30e1, 0xf000 },
+ { 0x30e2, 0x0000 },
+ { 0x30e3, 0xf000 },
+ { 0x30e4, 0x0000 },
+ { 0x30e5, 0xf000 },
+ { 0x30e6, 0x0000 },
+ { 0x30e7, 0xf000 },
+ { 0x30e8, 0x0000 },
+ { 0x30e9, 0xf000 },
+ { 0x30ea, 0x0000 },
+ { 0x30eb, 0xf000 },
+ { 0x30ec, 0x0000 },
+ { 0x30ed, 0xf000 },
+ { 0x30ee, 0x0000 },
+ { 0x30ef, 0xf000 },
+ { 0x30f0, 0x0228 },
+ { 0x30f1, 0x1a01 },
+ { 0x30f2, 0x0228 },
+ { 0x30f3, 0x1e00 },
+ { 0x30f4, 0x0228 },
+ { 0x30f5, 0x1f00 },
+ { 0x30f6, 0x6228 },
+ { 0x30f7, 0xf800 },
+ { 0x30f8, 0x0000 },
+ { 0x30f9, 0xf000 },
+ { 0x30fa, 0x0000 },
+ { 0x30fb, 0xf000 },
+ { 0x30fc, 0x0000 },
+ { 0x30fd, 0xf000 },
+ { 0x30fe, 0x0000 },
+ { 0x30ff, 0xf000 },
+ { 0x3100, 0x222b },
+ { 0x3101, 0x3a03 },
+ { 0x3102, 0x222b },
+ { 0x3103, 0x5803 },
+ { 0x3104, 0xe26f },
+ { 0x3105, 0x030d },
+ { 0x3106, 0x626f },
+ { 0x3107, 0x2c01 },
+ { 0x3108, 0xe26f },
+ { 0x3109, 0x4342 },
+ { 0x310a, 0xe26f },
+ { 0x310b, 0x73c0 },
+ { 0x310c, 0x026f },
+ { 0x310d, 0x0c00 },
+ { 0x310e, 0x022b },
+ { 0x310f, 0x1f01 },
+ { 0x3110, 0x022b },
+ { 0x3111, 0x1e01 },
+ { 0x3112, 0x022b },
+ { 0x3113, 0xfa00 },
+ { 0x3114, 0x0000 },
+ { 0x3115, 0xf000 },
+ { 0x3116, 0x0000 },
+ { 0x3117, 0xf000 },
+ { 0x3118, 0x0000 },
+ { 0x3119, 0xf000 },
+ { 0x311a, 0x0000 },
+ { 0x311b, 0xf000 },
+ { 0x311c, 0x0000 },
+ { 0x311d, 0xf000 },
+ { 0x311e, 0x0000 },
+ { 0x311f, 0xf000 },
+ { 0x3120, 0x022b },
+ { 0x3121, 0x0a01 },
+ { 0x3122, 0x022b },
+ { 0x3123, 0x1e00 },
+ { 0x3124, 0x022b },
+ { 0x3125, 0x1f00 },
+ { 0x3126, 0x622b },
+ { 0x3127, 0xf800 },
+ { 0x3128, 0x0000 },
+ { 0x3129, 0xf000 },
+ { 0x312a, 0x0000 },
+ { 0x312b, 0xf000 },
+ { 0x312c, 0x0000 },
+ { 0x312d, 0xf000 },
+ { 0x312e, 0x0000 },
+ { 0x312f, 0xf000 },
+ { 0x3130, 0x0000 },
+ { 0x3131, 0xf000 },
+ { 0x3132, 0x0000 },
+ { 0x3133, 0xf000 },
+ { 0x3134, 0x0000 },
+ { 0x3135, 0xf000 },
+ { 0x3136, 0x0000 },
+ { 0x3137, 0xf000 },
+ { 0x3138, 0x0000 },
+ { 0x3139, 0xf000 },
+ { 0x313a, 0x0000 },
+ { 0x313b, 0xf000 },
+ { 0x313c, 0x0000 },
+ { 0x313d, 0xf000 },
+ { 0x313e, 0x0000 },
+ { 0x313f, 0xf000 },
+ { 0x3140, 0x0000 },
+ { 0x3141, 0xf000 },
+ { 0x3142, 0x0000 },
+ { 0x3143, 0xf000 },
+ { 0x3144, 0x0000 },
+ { 0x3145, 0xf000 },
+ { 0x3146, 0x0000 },
+ { 0x3147, 0xf000 },
+ { 0x3148, 0x0000 },
+ { 0x3149, 0xf000 },
+ { 0x314a, 0x0000 },
+ { 0x314b, 0xf000 },
+ { 0x314c, 0x0000 },
+ { 0x314d, 0xf000 },
+ { 0x314e, 0x0000 },
+ { 0x314f, 0xf000 },
+ { 0x3150, 0x0000 },
+ { 0x3151, 0xf000 },
+ { 0x3152, 0x0000 },
+ { 0x3153, 0xf000 },
+ { 0x3154, 0x0000 },
+ { 0x3155, 0xf000 },
+ { 0x3156, 0x0000 },
+ { 0x3157, 0xf000 },
+ { 0x3158, 0x0000 },
+ { 0x3159, 0xf000 },
+ { 0x315a, 0x0000 },
+ { 0x315b, 0xf000 },
+ { 0x315c, 0x0000 },
+ { 0x315d, 0xf000 },
+ { 0x315e, 0x0000 },
+ { 0x315f, 0xf000 },
+ { 0x3160, 0x0000 },
+ { 0x3161, 0xf000 },
+ { 0x3162, 0x0000 },
+ { 0x3163, 0xf000 },
+ { 0x3164, 0x0000 },
+ { 0x3165, 0xf000 },
+ { 0x3166, 0x0000 },
+ { 0x3167, 0xf000 },
+ { 0x3168, 0x0000 },
+ { 0x3169, 0xf000 },
+ { 0x316a, 0x0000 },
+ { 0x316b, 0xf000 },
+ { 0x316c, 0x0000 },
+ { 0x316d, 0xf000 },
+ { 0x316e, 0x0000 },
+ { 0x316f, 0xf000 },
+ { 0x3170, 0x0000 },
+ { 0x3171, 0xf000 },
+ { 0x3172, 0x0000 },
+ { 0x3173, 0xf000 },
+ { 0x3174, 0x0000 },
+ { 0x3175, 0xf000 },
+ { 0x3176, 0x0000 },
+ { 0x3177, 0xf000 },
+ { 0x3178, 0x0000 },
+ { 0x3179, 0xf000 },
+ { 0x317a, 0x0000 },
+ { 0x317b, 0xf000 },
+ { 0x317c, 0x0000 },
+ { 0x317d, 0xf000 },
+ { 0x317e, 0x0000 },
+ { 0x317f, 0xf000 },
+ { 0x3180, 0x2001 },
+ { 0x3181, 0xf101 },
+ { 0x3182, 0x0000 },
+ { 0x3183, 0xf000 },
+ { 0x3184, 0x0000 },
+ { 0x3185, 0xf000 },
+ { 0x3186, 0x0000 },
+ { 0x3187, 0xf000 },
+ { 0x3188, 0x0000 },
+ { 0x3189, 0xf000 },
+ { 0x318a, 0x0000 },
+ { 0x318b, 0xf000 },
+ { 0x318c, 0x0000 },
+ { 0x318d, 0xf000 },
+ { 0x318e, 0x0000 },
+ { 0x318f, 0xf000 },
+ { 0x3190, 0x0000 },
+ { 0x3191, 0xf000 },
+ { 0x3192, 0x0000 },
+ { 0x3193, 0xf000 },
+ { 0x3194, 0x0000 },
+ { 0x3195, 0xf000 },
+ { 0x3196, 0x0000 },
+ { 0x3197, 0xf000 },
+ { 0x3198, 0x0000 },
+ { 0x3199, 0xf000 },
+ { 0x319a, 0x0000 },
+ { 0x319b, 0xf000 },
+ { 0x319c, 0x0000 },
+ { 0x319d, 0xf000 },
+ { 0x319e, 0x0000 },
+ { 0x319f, 0xf000 },
+ { 0x31a0, 0x0000 },
+ { 0x31a1, 0xf000 },
+ { 0x31a2, 0x0000 },
+ { 0x31a3, 0xf000 },
+ { 0x31a4, 0x0000 },
+ { 0x31a5, 0xf000 },
+ { 0x31a6, 0x0000 },
+ { 0x31a7, 0xf000 },
+ { 0x31a8, 0x0000 },
+ { 0x31a9, 0xf000 },
+ { 0x31aa, 0x0000 },
+ { 0x31ab, 0xf000 },
+ { 0x31ac, 0x0000 },
+ { 0x31ad, 0xf000 },
+ { 0x31ae, 0x0000 },
+ { 0x31af, 0xf000 },
+ { 0x31b0, 0x0000 },
+ { 0x31b1, 0xf000 },
+ { 0x31b2, 0x0000 },
+ { 0x31b3, 0xf000 },
+ { 0x31b4, 0x0000 },
+ { 0x31b5, 0xf000 },
+ { 0x31b6, 0x0000 },
+ { 0x31b7, 0xf000 },
+ { 0x31b8, 0x0000 },
+ { 0x31b9, 0xf000 },
+ { 0x31ba, 0x0000 },
+ { 0x31bb, 0xf000 },
+ { 0x31bc, 0x0000 },
+ { 0x31bd, 0xf000 },
+ { 0x31be, 0x0000 },
+ { 0x31bf, 0xf000 },
+ { 0x31c0, 0x0000 },
+ { 0x31c1, 0xf000 },
+ { 0x31c2, 0x0000 },
+ { 0x31c3, 0xf000 },
+ { 0x31c4, 0x0000 },
+ { 0x31c5, 0xf000 },
+ { 0x31c6, 0x0000 },
+ { 0x31c7, 0xf000 },
+ { 0x31c8, 0x0000 },
+ { 0x31c9, 0xf000 },
+ { 0x31ca, 0x0000 },
+ { 0x31cb, 0xf000 },
+ { 0x31cc, 0x0000 },
+ { 0x31cd, 0xf000 },
+ { 0x31ce, 0x0000 },
+ { 0x31cf, 0xf000 },
+ { 0x31d0, 0x0000 },
+ { 0x31d1, 0xf000 },
+ { 0x31d2, 0x0000 },
+ { 0x31d3, 0xf000 },
+ { 0x31d4, 0x0000 },
+ { 0x31d5, 0xf000 },
+ { 0x31d6, 0x0000 },
+ { 0x31d7, 0xf000 },
+ { 0x31d8, 0x0000 },
+ { 0x31d9, 0xf000 },
+ { 0x31da, 0x0000 },
+ { 0x31db, 0xf000 },
+ { 0x31dc, 0x0000 },
+ { 0x31dd, 0xf000 },
+ { 0x31de, 0x0000 },
+ { 0x31df, 0xf000 },
+ { 0x31e0, 0x0000 },
+ { 0x31e1, 0xf000 },
+ { 0x31e2, 0x0000 },
+ { 0x31e3, 0xf000 },
+ { 0x31e4, 0x0000 },
+ { 0x31e5, 0xf000 },
+ { 0x31e6, 0x0000 },
+ { 0x31e7, 0xf000 },
+ { 0x31e8, 0x0000 },
+ { 0x31e9, 0xf000 },
+ { 0x31ea, 0x0000 },
+ { 0x31eb, 0xf000 },
+ { 0x31ec, 0x0000 },
+ { 0x31ed, 0xf000 },
+ { 0x31ee, 0x0000 },
+ { 0x31ef, 0xf000 },
+ { 0x31f0, 0x0000 },
+ { 0x31f1, 0xf000 },
+ { 0x31f2, 0x0000 },
+ { 0x31f3, 0xf000 },
+ { 0x31f4, 0x0000 },
+ { 0x31f5, 0xf000 },
+ { 0x31f6, 0x0000 },
+ { 0x31f7, 0xf000 },
+ { 0x31f8, 0x0000 },
+ { 0x31f9, 0xf000 },
+ { 0x31fa, 0x0000 },
+ { 0x31fb, 0xf000 },
+ { 0x31fc, 0x0000 },
+ { 0x31fd, 0xf000 },
+ { 0x31fe, 0x0000 },
+ { 0x31ff, 0xf000 },
+ { 0x024d, 0xff50 },
+ { 0x0252, 0xff50 },
+ { 0x0259, 0x0112 },
+ { 0x025e, 0x0112 },
+};
+
+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 regmap *regmap = codec->control_data;
+ const struct reg_default *patch = NULL;
+ int i, patch_size;
+
+ switch (arizona->rev) {
+ case 0:
+ patch = wm5102_sysclk_reva_patch;
+ patch_size = ARRAY_SIZE(wm5102_sysclk_reva_patch);
+ break;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (patch)
+ for (i = 0; i < patch_size; i++)
+ regmap_write(regmap, patch[i].reg,
+ patch[i].def);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static const struct snd_kcontrol_new wm5102_snd_controls[] = {
SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
ARIZONA_IN1_OSR_SHIFT, 1, 0),
@@ -297,7 +847,7 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux =
static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
- 0, NULL, 0),
+ 0, wm5102_sysclk_ev, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 5421fd9fbcb5..4c0a8e496131 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -782,7 +782,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
wm8978->mclk_idx = -1;
f_sel = wm8978->f_mclk;
} else {
- if (!wm8978->f_pllout) {
+ if (!wm8978->f_opclk) {
/* We only enter here, if OPCLK is not used */
int ret = wm8978_configure_pll(codec);
if (ret < 0)
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
index b9f16598324c..2ba08148655f 100644
--- a/sound/soc/kirkwood/kirkwood-dma.c
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -71,7 +71,6 @@ static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
__func__, cause);
writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
- return IRQ_HANDLED;
}
/* we've enabled only bytes interrupts ... */
@@ -178,7 +177,7 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
}
dram = mv_mbus_dram_info();
- addr = virt_to_phys(substream->dma_buffer.area);
+ addr = substream->dma_buffer.addr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
prdata->play_stream = substream;
kirkwood_dma_conf_mbus_windows(priv->io,
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index 542538d10ab7..1d5db484d2df 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -95,7 +95,7 @@ static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
do {
cpu_relax();
value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
- value &= KIRKWOOD_DCO_SPCR_STATUS;
+ value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
} while (value == 0);
}
@@ -180,67 +180,72 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
- unsigned long value;
-
- /*
- * specs says KIRKWOOD_PLAYCTL must be read 2 times before
- * changing it. So read 1 time here and 1 later.
- */
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ uint32_t ctl, value;
+
+ ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
+ if (ctl & KIRKWOOD_PLAYCTL_PAUSE) {
+ unsigned timeout = 5000;
+ /*
+ * The Armada510 spec says that if we enter pause mode, the
+ * busy bit must be read back as clear _twice_. Make sure
+ * we respect that otherwise we get DMA underruns.
+ */
+ do {
+ value = ctl;
+ ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
+ if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
+ break;
+ udelay(1);
+ } while (timeout--);
+
+ if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
+ dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
+ ctl);
+ }
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- /* stop audio, enable interrupts */
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
- value |= KIRKWOOD_PLAYCTL_PAUSE;
- writel(value, priv->io + KIRKWOOD_PLAYCTL);
-
value = readl(priv->io + KIRKWOOD_INT_MASK);
value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
writel(value, priv->io + KIRKWOOD_INT_MASK);
/* configure audio & enable i2s playback */
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
- value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
- value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
+ ctl &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
+ ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
| KIRKWOOD_PLAYCTL_SPDIF_EN);
if (priv->burst == 32)
- value |= KIRKWOOD_PLAYCTL_BURST_32;
+ ctl |= KIRKWOOD_PLAYCTL_BURST_32;
else
- value |= KIRKWOOD_PLAYCTL_BURST_128;
- value |= KIRKWOOD_PLAYCTL_I2S_EN;
- writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ ctl |= KIRKWOOD_PLAYCTL_BURST_128;
+ ctl |= KIRKWOOD_PLAYCTL_I2S_EN;
+ writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;
case SNDRV_PCM_TRIGGER_STOP:
/* stop audio, disable interrupts */
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
- value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
- writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
+ writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
value = readl(priv->io + KIRKWOOD_INT_MASK);
value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
writel(value, priv->io + KIRKWOOD_INT_MASK);
/* disable all playbacks */
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
- value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
- writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+ writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
- value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
- writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
+ writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- value = readl(priv->io + KIRKWOOD_PLAYCTL);
- value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
- writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
+ writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
break;
default:
@@ -260,11 +265,6 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- /* stop audio, enable interrupts */
- value = readl(priv->io + KIRKWOOD_RECCTL);
- value |= KIRKWOOD_RECCTL_PAUSE;
- writel(value, priv->io + KIRKWOOD_RECCTL);
-
value = readl(priv->io + KIRKWOOD_INT_MASK);
value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
writel(value, priv->io + KIRKWOOD_INT_MASK);
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index aa037b292f3d..c294fbb523fc 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -523,16 +523,24 @@ static int mxs_saif_trigger(struct snd_pcm_substream *substream, int cmd,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
/*
- * write a data to saif data register to trigger
- * the transfer
+ * write data to saif data register to trigger
+ * the transfer.
+ * For 24-bit format the 32-bit FIFO register stores
+ * only one channel, so we need to write twice.
+ * This is also safe for the other non 24-bit formats.
*/
__raw_writel(0, saif->base + SAIF_DATA);
+ __raw_writel(0, saif->base + SAIF_DATA);
} else {
/*
- * read a data from saif data register to trigger
- * the receive
+ * read data from saif data register to trigger
+ * the receive.
+ * For 24-bit format the 32-bit FIFO register stores
+ * only one channel, so we need to read twice.
+ * This is also safe for the other non 24-bit formats.
*/
__raw_readl(saif->base + SAIF_DATA);
+ __raw_readl(saif->base + SAIF_DATA);
}
master_saif->ongoing = 1;
@@ -812,3 +820,4 @@ module_platform_driver(mxs_saif_driver);
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
MODULE_DESCRIPTION("MXS ASoC SAIF driver");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mxs-saif");
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index e7b83179aca2..3c7c3a59ed39 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -207,6 +207,8 @@ config SND_SOC_BELLS
select SND_SOC_WM5102
select SND_SOC_WM5110
select SND_SOC_WM9081
+ select SND_SOC_WM0010
+ select SND_SOC_WM1250_EV1
config SND_SOC_LOWLAND
tristate "Audio support for Wolfson Lowland"
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
index b0d46d63d55e..a2ca1567b9e4 100644
--- a/sound/soc/samsung/bells.c
+++ b/sound/soc/samsung/bells.c
@@ -212,7 +212,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = {
{
.name = "Sub",
.stream_name = "Sub",
- .cpu_dai_name = "wm5110-aif3",
+ .cpu_dai_name = "wm5102-aif3",
.codec_dai_name = "wm9081-hifi",
.codec_name = "wm9081.1-006c",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d1198627fc40..10d21be383f6 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2786,8 +2786,9 @@ int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
val = (ucontrol->value.integer.value[0] + min) & mask;
val = val << shift;
- if (snd_soc_update_bits_locked(codec, reg, val_mask, val))
- return err;
+ err = snd_soc_update_bits_locked(codec, reg, val_mask, val);
+ if (err < 0)
+ return err;
if (snd_soc_volsw_is_stereo(mc)) {
val_mask = mask << rshift;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index d0a4be38dc0f..6e35bcae02df 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -3745,7 +3745,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
- list_for_each_entry(codec, &card->codec_dev_list, list) {
+ list_for_each_entry(codec, &card->codec_dev_list, card_list) {
soc_dapm_shutdown_codec(&codec->dapm);
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY)
snd_soc_dapm_set_bias_level(&codec->dapm,
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 282f0fc9fed1..dbf7999d18b4 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -559,9 +559,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
return;
card = chip->card;
- mutex_lock(&register_mutex);
down_write(&chip->shutdown_rwsem);
chip->shutdown = 1;
+ up_write(&chip->shutdown_rwsem);
+
+ mutex_lock(&register_mutex);
chip->num_interfaces--;
if (chip->num_interfaces <= 0) {
snd_card_disconnect(card);
@@ -582,11 +584,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
snd_usb_mixer_disconnect(p);
}
usb_chip[chip->index] = NULL;
- up_write(&chip->shutdown_rwsem);
mutex_unlock(&register_mutex);
snd_card_free_when_closed(card);
} else {
- up_write(&chip->shutdown_rwsem);
mutex_unlock(&register_mutex);
}
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index c83f6143c0eb..eeefbce3873c 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -148,6 +148,7 @@ struct snd_usb_midi_out_endpoint {
struct snd_usb_midi_out_endpoint* ep;
struct snd_rawmidi_substream *substream;
int active;
+ bool autopm_reference;
uint8_t cable; /* cable number << 4 */
uint8_t state;
#define STATE_UNKNOWN 0
@@ -1076,7 +1077,8 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
return -ENXIO;
}
err = usb_autopm_get_interface(umidi->iface);
- if (err < 0)
+ port->autopm_reference = err >= 0;
+ if (err < 0 && err != -EACCES)
return -EIO;
substream->runtime->private_data = port;
port->state = STATE_UNKNOWN;
@@ -1087,9 +1089,11 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
{
struct snd_usb_midi* umidi = substream->rmidi->private_data;
+ struct usbmidi_out_port *port = substream->runtime->private_data;
substream_open(substream, 0);
- usb_autopm_put_interface(umidi->iface);
+ if (port->autopm_reference)
+ usb_autopm_put_interface(umidi->iface);
return 0;
}
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 5c12a3fe8c3e..ef6fa24fc473 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -459,7 +459,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
return ret;
if (subs->sync_endpoint)
- ret = snd_usb_endpoint_set_params(subs->data_endpoint,
+ ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
subs->pcm_format,
subs->channels,
subs->period_bytes,
diff --git a/tools/Makefile b/tools/Makefile
index 3ae43947a171..1f9a529fe544 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -31,44 +31,44 @@ help:
@echo ' clean: a summary clean target to clean _all_ folders'
cpupower: FORCE
- $(QUIET_SUBDIR0)power/$@/ $(QUIET_SUBDIR1)
+ $(call descend,power/$@)
firewire lguest perf usb virtio vm: FORCE
- $(QUIET_SUBDIR0)$@/ $(QUIET_SUBDIR1)
+ $(call descend,$@)
selftests: FORCE
- $(QUIET_SUBDIR0)testing/$@/ $(QUIET_SUBDIR1)
+ $(call descend,testing/$@)
turbostat x86_energy_perf_policy: FORCE
- $(QUIET_SUBDIR0)power/x86/$@/ $(QUIET_SUBDIR1)
+ $(call descend,power/x86/$@)
cpupower_install:
- $(QUIET_SUBDIR0)power/$(@:_install=)/ $(QUIET_SUBDIR1) install
+ $(call descend,power/$(@:_install=),install)
firewire_install lguest_install perf_install usb_install virtio_install vm_install:
- $(QUIET_SUBDIR0)$(@:_install=)/ $(QUIET_SUBDIR1) install
+ $(call descend,$(@:_install=),install)
selftests_install:
- $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) install
+ $(call descend,testing/$(@:_clean=),install)
turbostat_install x86_energy_perf_policy_install:
- $(QUIET_SUBDIR0)power/x86/$(@:_install=)/ $(QUIET_SUBDIR1) install
+ $(call descend,power/x86/$(@:_install=),install)
install: cpupower_install firewire_install lguest_install perf_install \
selftests_install turbostat_install usb_install virtio_install \
vm_install x86_energy_perf_policy_install
cpupower_clean:
- $(QUIET_SUBDIR0)power/cpupower/ $(QUIET_SUBDIR1) clean
+ $(call descend,power/cpupower,clean)
firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
- $(QUIET_SUBDIR0)$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+ $(call descend,$(@:_clean=),clean)
selftests_clean:
- $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+ $(call descend,testing/$(@:_clean=),clean)
turbostat_clean x86_energy_perf_policy_clean:
- $(QUIET_SUBDIR0)power/x86/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+ $(call descend,power/x86/$(@:_clean=),clean)
clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \
turbostat_clean usb_clean virtio_clean vm_clean \
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 00deed4d6159..0a619af5be43 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -169,7 +169,34 @@ endif
### --- END CONFIGURATION SECTION ---
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
+ifneq ($(objtree),)
+#$(info Determined 'objtree' to be $(objtree))
+endif
+
+ifneq ($(OUTPUT),)
+#$(info Determined 'OUTPUT' to be $(OUTPUT))
+endif
+
+BASIC_CFLAGS = \
+ -Iutil/include \
+ -Iarch/$(ARCH)/include \
+ $(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
+ -I$(srctree)/arch/$(ARCH)/include/uapi \
+ -I$(srctree)/arch/$(ARCH)/include \
+ $(if $(objtree),-I$(objtree)/include/generated/uapi) \
+ -I$(srctree)/include/uapi \
+ -I$(srctree)/include \
+ -I$(OUTPUT)util \
+ -Iutil \
+ -I. \
+ -I$(TRACE_EVENT_DIR) \
+ -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
BASIC_LDFLAGS =
# Guard against environment variables
diff --git a/tools/perf/arch/x86/include/perf_regs.h b/tools/perf/arch/x86/include/perf_regs.h
index 46fc9f15c6b3..7fcdcdbee917 100644
--- a/tools/perf/arch/x86/include/perf_regs.h
+++ b/tools/perf/arch/x86/include/perf_regs.h
@@ -3,7 +3,7 @@
#include <stdlib.h>
#include "../../util/types.h"
-#include "../../../../../arch/x86/include/asm/perf_regs.h"
+#include <asm/perf_regs.h>
#ifndef ARCH_X86_64
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index 260abc535b5b..283b4397e397 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -22,9 +22,10 @@
#include <pthread.h>
#include <math.h>
-#include "../../arch/x86/include/asm/svm.h"
-#include "../../arch/x86/include/asm/vmx.h"
-#include "../../arch/x86/include/asm/kvm.h"
+#if defined(__i386__) || defined(__x86_64__)
+#include <asm/svm.h>
+#include <asm/vmx.h>
+#include <asm/kvm.h>
struct event_key {
#define INVALID_KEY (~0ULL)
@@ -58,7 +59,7 @@ struct kvm_event_key {
};
-struct perf_kvm;
+struct perf_kvm_stat;
struct kvm_events_ops {
bool (*is_begin_event)(struct perf_evsel *evsel,
@@ -66,7 +67,7 @@ struct kvm_events_ops {
struct event_key *key);
bool (*is_end_event)(struct perf_evsel *evsel,
struct perf_sample *sample, struct event_key *key);
- void (*decode_key)(struct perf_kvm *kvm, struct event_key *key,
+ void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
char decode[20]);
const char *name;
};
@@ -79,7 +80,7 @@ struct exit_reasons_table {
#define EVENTS_BITS 12
#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
-struct perf_kvm {
+struct perf_kvm_stat {
struct perf_tool tool;
struct perf_session *session;
@@ -146,7 +147,7 @@ static struct exit_reasons_table svm_exit_reasons[] = {
SVM_EXIT_REASONS
};
-static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
+static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
{
int i = kvm->exit_reasons_size;
struct exit_reasons_table *tbl = kvm->exit_reasons;
@@ -162,7 +163,7 @@ static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
return "UNKNOWN";
}
-static void exit_event_decode_key(struct perf_kvm *kvm,
+static void exit_event_decode_key(struct perf_kvm_stat *kvm,
struct event_key *key,
char decode[20])
{
@@ -228,7 +229,7 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
return false;
}
-static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused,
+static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
struct event_key *key,
char decode[20])
{
@@ -271,7 +272,7 @@ static bool ioport_event_end(struct perf_evsel *evsel,
return kvm_entry_event(evsel);
}
-static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused,
+static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
struct event_key *key,
char decode[20])
{
@@ -286,7 +287,7 @@ static struct kvm_events_ops ioport_events = {
.name = "IO Port Access"
};
-static bool register_kvm_events_ops(struct perf_kvm *kvm)
+static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
{
bool ret = true;
@@ -311,7 +312,7 @@ struct vcpu_event_record {
};
-static void init_kvm_event_record(struct perf_kvm *kvm)
+static void init_kvm_event_record(struct perf_kvm_stat *kvm)
{
int i;
@@ -360,7 +361,7 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
return event;
}
-static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
+static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
struct event_key *key)
{
struct kvm_event *event;
@@ -381,7 +382,7 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
return event;
}
-static bool handle_begin_event(struct perf_kvm *kvm,
+static bool handle_begin_event(struct perf_kvm_stat *kvm,
struct vcpu_event_record *vcpu_record,
struct event_key *key, u64 timestamp)
{
@@ -425,7 +426,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
return true;
}
-static bool handle_end_event(struct perf_kvm *kvm,
+static bool handle_end_event(struct perf_kvm_stat *kvm,
struct vcpu_event_record *vcpu_record,
struct event_key *key,
u64 timestamp)
@@ -486,7 +487,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
return thread->priv;
}
-static bool handle_kvm_event(struct perf_kvm *kvm,
+static bool handle_kvm_event(struct perf_kvm_stat *kvm,
struct thread *thread,
struct perf_evsel *evsel,
struct perf_sample *sample)
@@ -541,7 +542,7 @@ static struct kvm_event_key keys[] = {
{ NULL, NULL }
};
-static bool select_key(struct perf_kvm *kvm)
+static bool select_key(struct perf_kvm_stat *kvm)
{
int i;
@@ -577,7 +578,8 @@ static void insert_to_result(struct rb_root *result, struct kvm_event *event,
rb_insert_color(&event->rb, result);
}
-static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event)
+static void
+update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
{
int vcpu = kvm->trace_vcpu;
@@ -590,7 +592,7 @@ static bool event_is_valid(struct kvm_event *event, int vcpu)
return !!get_event_count(event, vcpu);
}
-static void sort_result(struct perf_kvm *kvm)
+static void sort_result(struct perf_kvm_stat *kvm)
{
unsigned int i;
int vcpu = kvm->trace_vcpu;
@@ -627,7 +629,7 @@ static void print_vcpu_info(int vcpu)
pr_info("VCPU %d:\n\n", vcpu);
}
-static void print_result(struct perf_kvm *kvm)
+static void print_result(struct perf_kvm_stat *kvm)
{
char decode[20];
struct kvm_event *event;
@@ -670,7 +672,8 @@ static int process_sample_event(struct perf_tool *tool,
struct machine *machine)
{
struct thread *thread = machine__findnew_thread(machine, sample->tid);
- struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool);
+ struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
+ tool);
if (thread == NULL) {
pr_debug("problem processing %d event, skipping it.\n",
@@ -701,7 +704,7 @@ static int get_cpu_isa(struct perf_session *session)
return isa;
}
-static int read_events(struct perf_kvm *kvm)
+static int read_events(struct perf_kvm_stat *kvm)
{
int ret;
@@ -750,7 +753,7 @@ static bool verify_vcpu(int vcpu)
return true;
}
-static int kvm_events_report_vcpu(struct perf_kvm *kvm)
+static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
{
int ret = -EINVAL;
int vcpu = kvm->trace_vcpu;
@@ -798,7 +801,8 @@ static const char * const record_args[] = {
_p; \
})
-static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
+static int
+kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
{
unsigned int rec_argc, i, j;
const char **rec_argv;
@@ -821,7 +825,8 @@ static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
-static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv)
+static int
+kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
{
const struct option kvm_events_report_options[] = {
OPT_STRING(0, "event", &kvm->report_event, "report event",
@@ -864,24 +869,37 @@ static void print_kvm_stat_usage(void)
printf("\nOtherwise, it is the alias of 'perf stat':\n");
}
-static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv)
+static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
{
+ struct perf_kvm_stat kvm = {
+ .file_name = file_name,
+
+ .trace_vcpu = -1,
+ .report_event = "vmexit",
+ .sort_key = "sample",
+
+ .exit_reasons = svm_exit_reasons,
+ .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
+ .exit_reasons_isa = "SVM",
+ };
+
if (argc == 1) {
print_kvm_stat_usage();
goto perf_stat;
}
if (!strncmp(argv[1], "rec", 3))
- return kvm_events_record(kvm, argc - 1, argv + 1);
+ return kvm_events_record(&kvm, argc - 1, argv + 1);
if (!strncmp(argv[1], "rep", 3))
- return kvm_events_report(kvm, argc - 1 , argv + 1);
+ return kvm_events_report(&kvm, argc - 1 , argv + 1);
perf_stat:
return cmd_stat(argc, argv, NULL);
}
+#endif
-static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
+static int __cmd_record(const char *file_name, int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
@@ -890,7 +908,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("record");
rec_argv[i++] = strdup("-o");
- rec_argv[i++] = strdup(kvm->file_name);
+ rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
@@ -899,7 +917,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
-static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
+static int __cmd_report(const char *file_name, int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
@@ -908,7 +926,7 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("report");
rec_argv[i++] = strdup("-i");
- rec_argv[i++] = strdup(kvm->file_name);
+ rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
@@ -917,7 +935,8 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
return cmd_report(i, rec_argv, NULL);
}
-static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
+static int
+__cmd_buildid_list(const char *file_name, int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
@@ -926,7 +945,7 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("buildid-list");
rec_argv[i++] = strdup("-i");
- rec_argv[i++] = strdup(kvm->file_name);
+ rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
@@ -937,20 +956,12 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
{
- struct perf_kvm kvm = {
- .trace_vcpu = -1,
- .report_event = "vmexit",
- .sort_key = "sample",
-
- .exit_reasons = svm_exit_reasons,
- .exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
- .exit_reasons_isa = "SVM",
- };
+ const char *file_name;
const struct option kvm_options[] = {
- OPT_STRING('i', "input", &kvm.file_name, "file",
+ OPT_STRING('i', "input", &file_name, "file",
"Input file name"),
- OPT_STRING('o', "output", &kvm.file_name, "file",
+ OPT_STRING('o', "output", &file_name, "file",
"Output file name"),
OPT_BOOLEAN(0, "guest", &perf_guest,
"Collect guest os data"),
@@ -985,32 +996,34 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
if (!perf_host)
perf_guest = 1;
- if (!kvm.file_name) {
+ if (!file_name) {
if (perf_host && !perf_guest)
- kvm.file_name = strdup("perf.data.host");
+ file_name = strdup("perf.data.host");
else if (!perf_host && perf_guest)
- kvm.file_name = strdup("perf.data.guest");
+ file_name = strdup("perf.data.guest");
else
- kvm.file_name = strdup("perf.data.kvm");
+ file_name = strdup("perf.data.kvm");
- if (!kvm.file_name) {
+ if (!file_name) {
pr_err("Failed to allocate memory for filename\n");
return -ENOMEM;
}
}
if (!strncmp(argv[0], "rec", 3))
- return __cmd_record(&kvm, argc, argv);
+ return __cmd_record(file_name, argc, argv);
else if (!strncmp(argv[0], "rep", 3))
- return __cmd_report(&kvm, argc, argv);
+ return __cmd_report(file_name, argc, argv);
else if (!strncmp(argv[0], "diff", 4))
return cmd_diff(argc, argv, NULL);
else if (!strncmp(argv[0], "top", 3))
return cmd_top(argc, argv, NULL);
else if (!strncmp(argv[0], "buildid-list", 12))
- return __cmd_buildid_list(&kvm, argc, argv);
+ return __cmd_buildid_list(file_name, argc, argv);
+#if defined(__i386__) || defined(__x86_64__)
else if (!strncmp(argv[0], "stat", 4))
- return kvm_cmd_stat(&kvm, argc, argv);
+ return kvm_cmd_stat(file_name, argc, argv);
+#endif
else
usage_with_options(kvm_usage, kvm_options);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 484f26cc0c00..5acd6e8e658b 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -15,7 +15,7 @@
#include "util/thread_map.h"
#include "util/pmu.h"
#include "event-parse.h"
-#include "../../include/linux/hw_breakpoint.h"
+#include <linux/hw_breakpoint.h>
#include <sys/mman.h>
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index c50985eaec41..238f923f2218 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -5,8 +5,9 @@ struct winsize;
void get_term_dimensions(struct winsize *ws);
+#include <asm/unistd.h>
+
#if defined(__i386__)
-#include "../../arch/x86/include/asm/unistd.h"
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
@@ -16,7 +17,6 @@ void get_term_dimensions(struct winsize *ws);
#endif
#if defined(__x86_64__)
-#include "../../arch/x86/include/asm/unistd.h"
#define rmb() asm volatile("lfence" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
@@ -26,20 +26,17 @@ void get_term_dimensions(struct winsize *ws);
#endif
#ifdef __powerpc__
-#include "../../arch/powerpc/include/asm/unistd.h"
#define rmb() asm volatile ("sync" ::: "memory")
#define cpu_relax() asm volatile ("" ::: "memory");
#define CPUINFO_PROC "cpu"
#endif
#ifdef __s390__
-#include "../../arch/s390/include/asm/unistd.h"
#define rmb() asm volatile("bcr 15,0" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory");
#endif
#ifdef __sh__
-#include "../../arch/sh/include/asm/unistd.h"
#if defined(__SH4A__) || defined(__SH5__)
# define rmb() asm volatile("synco" ::: "memory")
#else
@@ -50,35 +47,30 @@ void get_term_dimensions(struct winsize *ws);
#endif
#ifdef __hppa__
-#include "../../arch/parisc/include/asm/unistd.h"
#define rmb() asm volatile("" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory");
#define CPUINFO_PROC "cpu"
#endif
#ifdef __sparc__
-#include "../../arch/sparc/include/uapi/asm/unistd.h"
#define rmb() asm volatile("":::"memory")
#define cpu_relax() asm volatile("":::"memory")
#define CPUINFO_PROC "cpu"
#endif
#ifdef __alpha__
-#include "../../arch/alpha/include/asm/unistd.h"
#define rmb() asm volatile("mb" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory")
#define CPUINFO_PROC "cpu model"
#endif
#ifdef __ia64__
-#include "../../arch/ia64/include/asm/unistd.h"
#define rmb() asm volatile ("mf" ::: "memory")
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
#define CPUINFO_PROC "model name"
#endif
#ifdef __arm__
-#include "../../arch/arm/include/asm/unistd.h"
/*
* Use the __kuser_memory_barrier helper in the CPU helper page. See
* arch/arm/kernel/entry-armv.S in the kernel source for details.
@@ -89,13 +81,11 @@ void get_term_dimensions(struct winsize *ws);
#endif
#ifdef __aarch64__
-#include "../../arch/arm64/include/asm/unistd.h"
#define rmb() asm volatile("dmb ld" ::: "memory")
#define cpu_relax() asm volatile("yield" ::: "memory")
#endif
#ifdef __mips__
-#include "../../arch/mips/include/asm/unistd.h"
#define rmb() asm volatile( \
".set mips2\n\t" \
"sync\n\t" \
@@ -112,7 +102,7 @@ void get_term_dimensions(struct winsize *ws);
#include <sys/types.h>
#include <sys/syscall.h>
-#include "../../include/uapi/linux/perf_event.h"
+#include <linux/perf_event.h>
#include "util/types.h"
#include <stdbool.h>
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 618d41140abd..d144d464ce39 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -18,8 +18,8 @@
#include "cpumap.h"
#include "thread_map.h"
#include "target.h"
-#include "../../../include/linux/hw_breakpoint.h"
-#include "../../../include/uapi/linux/perf_event.h"
+#include <linux/hw_breakpoint.h>
+#include <linux/perf_event.h>
#include "perf_regs.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 6f94d6dea00f..d99b476ef37c 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -3,7 +3,8 @@
#include <linux/list.h>
#include <stdbool.h>
-#include "../../../include/uapi/linux/perf_event.h"
+#include <stddef.h>
+#include <linux/perf_event.h>
#include "types.h"
#include "xyarray.h"
#include "cgroup.h"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7daad237dea5..566b84c695c8 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1378,6 +1378,8 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused,
str = tmp + 1;
fprintf(fp, "# node%u cpu list : %s\n", c, str);
+
+ str += strlen(str) + 1;
}
return;
error:
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 879d215cdac9..9bc00783f24f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -1,7 +1,7 @@
#ifndef __PERF_HEADER_H
#define __PERF_HEADER_H
-#include "../../../include/uapi/linux/perf_event.h"
+#include <linux/perf_event.h>
#include <sys/types.h>
#include <stdbool.h>
#include "types.h"
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
index 516ecd9ddd6e..6ef213b35ecd 100644
--- a/tools/perf/util/parse-events-test.c
+++ b/tools/perf/util/parse-events-test.c
@@ -3,7 +3,7 @@
#include "evsel.h"
#include "evlist.h"
#include "sysfs.h"
-#include "../../../include/linux/hw_breakpoint.h"
+#include <linux/hw_breakpoint.h>
#define TEST_ASSERT_VAL(text, cond) \
do { \
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 75c7b0fca6d9..6b6d03e93c3d 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1,4 +1,4 @@
-#include "../../../include/linux/hw_breakpoint.h"
+#include <linux/hw_breakpoint.h>
#include "util.h"
#include "../perf.h"
#include "evlist.h"
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 839230ceb18b..2820c407adb2 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -7,7 +7,7 @@
#include <linux/list.h>
#include <stdbool.h>
#include "types.h"
-#include "../../../include/uapi/linux/perf_event.h"
+#include <linux/perf_event.h>
#include "types.h"
struct list_head;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 39f3abac7744..fdeb8ac7c5d2 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -2,7 +2,7 @@
#define __PMU_H
#include <linux/bitops.h>
-#include "../../../include/uapi/linux/perf_event.h"
+#include <linux/perf_event.h>
enum {
PERF_PMU_FORMAT_VALUE_CONFIG,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index dd6426163ba6..0eae00ad5fe7 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -7,7 +7,7 @@
#include "symbol.h"
#include "thread.h"
#include <linux/rbtree.h>
-#include "../../../include/uapi/linux/perf_event.h"
+#include <linux/perf_event.h>
struct sample_queue;
struct ip_callchain;
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c
index 2eeb51baf077..cfa906882e2c 100644
--- a/tools/perf/util/strbuf.c
+++ b/tools/perf/util/strbuf.c
@@ -90,17 +90,17 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
if (!strbuf_avail(sb))
strbuf_grow(sb, 64);
va_start(ap, fmt);
- len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+ len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len < 0)
- die("your vscnprintf is broken");
+ die("your vsnprintf is broken");
if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
va_start(ap, fmt);
- len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
+ len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len > strbuf_avail(sb)) {
- die("this should not happen, your snprintf is broken");
+ die("this should not happen, your vsnprintf is broken");
}
}
strbuf_setlen(sb, sb->len + len);
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 2655ae9a3ad8..ea095abbe97e 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -206,8 +206,10 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
retval = pread(fd, msr, sizeof *msr, offset);
close(fd);
- if (retval != sizeof *msr)
+ if (retval != sizeof *msr) {
+ fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset);
return -1;
+ }
return 0;
}
@@ -1101,7 +1103,9 @@ void turbostat_loop()
restart:
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
- if (retval) {
+ if (retval < -1) {
+ exit(retval);
+ } else if (retval == -1) {
re_initialize();
goto restart;
}
@@ -1114,7 +1118,9 @@ restart:
}
sleep(interval_sec);
retval = for_all_cpus(get_counters, ODD_COUNTERS);
- if (retval) {
+ if (retval < -1) {
+ exit(retval);
+ } else if (retval == -1) {
re_initialize();
goto restart;
}
@@ -1126,7 +1132,9 @@ restart:
flush_stdout();
sleep(interval_sec);
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
- if (retval) {
+ if (retval < -1) {
+ exit(retval);
+ } else if (retval == -1) {
re_initialize();
goto restart;
}
@@ -1545,8 +1553,11 @@ void turbostat_init()
int fork_it(char **argv)
{
pid_t child_pid;
+ int status;
- for_all_cpus(get_counters, EVEN_COUNTERS);
+ status = for_all_cpus(get_counters, EVEN_COUNTERS);
+ if (status)
+ exit(status);
/* clear affinity side-effect of get_counters() */
sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
gettimeofday(&tv_even, (struct timezone *)NULL);
@@ -1556,7 +1567,6 @@ int fork_it(char **argv)
/* child */
execvp(argv[0], argv);
} else {
- int status;
/* parent */
if (child_pid == -1) {
@@ -1568,7 +1578,7 @@ int fork_it(char **argv)
signal(SIGQUIT, SIG_IGN);
if (waitpid(child_pid, &status, 0) == -1) {
perror("wait");
- exit(1);
+ exit(status);
}
}
/*
@@ -1585,7 +1595,7 @@ int fork_it(char **argv)
fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
- return 0;
+ return status;
}
void cmdline(int argc, char **argv)
@@ -1594,7 +1604,7 @@ void cmdline(int argc, char **argv)
progname = argv[0];
- while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) {
+ while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:")) != -1) {
switch (opt) {
case 'p':
show_core_only++;
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
index 96ce80a3743b..2964b96aa55f 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -1,8 +1,11 @@
-ifeq ("$(origin O)", "command line")
+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)
- OUTPUT := $(ABSOLUTE_O)/
+ OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/)
COMMAND_O := O=$(ABSOLUTE_O)
+ifeq ($(objtree),)
+ objtree := $(O)
+endif
endif
ifneq ($(OUTPUT),)
@@ -41,7 +44,16 @@ else
NO_SUBDIR = :
endif
-QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+#
+# Define a callable command for descending to a new directory
+#
+# Call by doing: $(call descend,directory[,target])
+#
+descend = \
+ +mkdir -p $(OUTPUT)$(1) && \
+ $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
+
+QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir
QUIET_SUBDIR1 =
ifneq ($(findstring $(MAKEFLAGS),s),s)
@@ -56,5 +68,10 @@ ifndef V
$(MAKE) $(PRINT_DIR) -C $$subdir
QUIET_FLEX = @echo ' ' FLEX $@;
QUIET_BISON = @echo ' ' BISON $@;
+
+ descend = \
+ @echo ' ' DESCEND $(1); \
+ mkdir -p $(OUTPUT)$(1) && \
+ $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2)
endif
endif